<commit_before>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file implements a class with static methods to describe the Xinvert routine. Examples of
// such 'descriptions' are how to calculate the size a of buffer or how to run the routine. These
// static methods are used by the correctness tester and the performance tester.
//
// =================================================================================================

#ifndef CLBLAST_TEST_ROUTINES_XINVERT_H_
#define CLBLAST_TEST_ROUTINES_XINVERT_H_

#include <vector>
#include <string>

#include "utilities/utilities.hpp"

namespace clblast {
// =================================================================================================

template <typename T>
StatusCode RunReference(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
  const bool is_upper = ((args.triangle == Triangle::kUpper && args.layout != Layout::kRowMajor) ||
                         (args.triangle == Triangle::kLower && args.layout == Layout::kRowMajor));

  // Data transfer from OpenCL to std::vector
  std::vector<T> a_mat_cpu(args.a_size, T{0.0});
  buffers.a_mat.Read(queue, args.a_size, a_mat_cpu);

  // Creates the output buffer
  std::vector<T> b_mat_cpu(args.b_size, T{0.0});

  // Helper variables
  const auto block_size = args.m;
  const auto num_blocks = CeilDiv(args.n, block_size);
  const auto a_ld = args.a_ld;
  const auto b_ld = block_size;

  // Checks for valid arguments
  if ((block_size == 0) || (args.n == 0)) {
    return StatusCode::kInvalidDimension;
  }
  if ((block_size % 16 != 0) || (block_size > 128)) {
    return StatusCode::kUnknownError;
  }

  // Loops over the amount of diagonal blocks of size args.m by args.m each
  for (auto block_id = size_t{0}; block_id < num_blocks; ++block_id) {
    const auto a_offset = block_id * (block_size + a_ld * block_size) + args.a_offset;
    const auto b_offset = block_id * block_size * block_size;

    // Inverts the diagonal elements of the matrix
    for (auto i = size_t{0}; i < block_size; ++i) {
      auto a_value = T{1.0};
      if (args.diagonal == Diagonal::kNonUnit) {
        if (i + block_id * block_size < args.n) {
          if (a_mat_cpu[i * a_ld + i + a_offset] == T{0.0}) { return StatusCode::kUnknownError; }
          a_value = T{1.0} / a_mat_cpu[i * a_ld + i + a_offset];
        }
      }
      b_mat_cpu[i * b_ld + i + b_offset] = a_value;
    }

    // Inverts the upper triangle row by row
    if (is_upper) {
      for (int i = static_cast<int>(block_size) - 2; i >= 0; --i) {
        for (auto j = static_cast<int>(block_size) - 1; j > i; --j) {
          auto sum = T{0.0};
          for (auto k = i + 1; k <= j; ++k) {
            auto a_value = T{0.0};
            if ((i + block_id * block_size < args.n) && (k + block_id * block_size < args.n)) {
              a_value = a_mat_cpu[k * a_ld + i + a_offset];
            }
            sum += a_value * b_mat_cpu[j * b_ld + k + b_offset];
          }
          b_mat_cpu[j * b_ld + i + b_offset] = - sum * b_mat_cpu[i * b_ld + i + b_offset];
        }
      }
    }

    // Inverts the lower triangle row by row
    else {
      for (auto i = size_t{1}; i < block_size; ++i) {
        for (auto j = size_t{0}; j < i; ++j) {
          auto sum = T{0.0};
          for (auto k = j; k < i; ++k) {
            auto a_value = T{0.0};
            if ((i + block_id * block_size < args.n) && (k + block_id * block_size < args.n)) {
              a_value = a_mat_cpu[k * a_ld + i + a_offset];
            }
            sum += a_value * b_mat_cpu[j * b_ld + k + b_offset];
          }
          b_mat_cpu[j * b_ld + i + b_offset] = - sum * b_mat_cpu[i * b_ld + i + b_offset];
        }
      }
    }
  }

  // Data transfer back to OpenCL
  buffers.b_mat.Write(queue, args.b_size, b_mat_cpu);
  return StatusCode::kSuccess;
}

// Half-precision version calling the above reference implementation after conversions
template <>
StatusCode RunReference<half>(const Arguments<half> &args, Buffers<half> &buffers, Queue &queue) {
  auto a_buffer2 = HalfToFloatBuffer(buffers.a_mat, queue());
  auto b_buffer2 = HalfToFloatBuffer(buffers.b_mat, queue());
  auto dummy = clblast::Buffer<float>(0);
  auto buffers2 = Buffers<float>{dummy, dummy, a_buffer2, b_buffer2, dummy, dummy, dummy};
  auto args2 = Arguments<float>();
  args2.a_size = args.a_size; args2.b_size = args.b_size;
  args2.a_ld = args.a_ld; args2.m = args.m; args2.n = args.n;
  args2.a_offset = args.a_offset;
  args2.layout = args.layout; args2.triangle = args.triangle; args2.diagonal = args.diagonal;
  auto status = RunReference(args2, buffers2, queue);
  FloatToHalfBuffer(buffers.b_mat, b_buffer2, queue());
  return status;
}

// =================================================================================================

// See comment at top of file for a description of the class
template <typename T>
class TestXinvert {
 public:

  // The BLAS level: 4 for the extra routines
  static size_t BLASLevel() { return 4; }

  // The list of arguments relevant for this routine
  static std::vector<std::string> GetOptions() {
    return {kArgN, kArgM,
            kArgLayout, kArgTriangle, kArgDiagonal,
            kArgALeadDim, kArgAOffset};
  }

  // Describes how to obtain the sizes of the buffers
  static size_t GetSizeA(const Arguments<T> &args) {
    return args.n * args.a_ld + args.a_offset;
  }
  static size_t GetSizeB(const Arguments<T> &args) {
    const auto block_size = args.m;
    const auto num_blocks = CeilDiv(args.n, block_size);
    return num_blocks * block_size * block_size;
  }

  // Describes how to set the sizes of all the buffers
  static void SetSizes(Arguments<T> &args) {
    args.a_size = GetSizeA(args);
    args.b_size = GetSizeB(args);
  }

  // Describes what the default values of the leading dimensions of the matrices are
  static size_t DefaultLDA(const Arguments<T> &args) { return args.n; }
  static size_t DefaultLDB(const Arguments<T> &) { return 1; } // N/A for this routine
  static size_t DefaultLDC(const Arguments<T> &) { return 1; } // N/A for this routine

  // Describes which omatcopyose options are relevant for this routine
  using Transposes = std::vector<Transpose>;
  static Transposes GetATransposes(const Transposes &) { return {}; } // N/A for this routine
  static Transposes GetBTransposes(const Transposes &) { return {}; } // N/A for this routine

  // Describes how to prepare the input data
  static void PrepareData(const Arguments<T>&, Queue&, const int, std::vector<T>&,
                          std::vector<T>&, std::vector<T>&, std::vector<T>&, std::vector<T>&,
                          std::vector<T>&, std::vector<T>&) {} // N/A for this routine

  // Describes how to run the CLBlast routine
  static StatusCode RunRoutine(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    try {
      auto event = cl_event{};
      auto inverter = Xinvert<T>(queue, &event);
      inverter.InvertMatrixDiagonalBlocks(args.layout, args.triangle, args.diagonal,
                                          args.n, args.m,
                                          buffers.a_mat, args.a_offset, args.a_ld,
                                          buffers.b_mat);
      clWaitForEvents(1, &event);
      clReleaseEvent(event);
    } catch (...) { return DispatchException(); }
    return StatusCode::kSuccess;
  }

  // Describes how to run a naive version of the routine (for correctness/performance comparison).
  // Note that a proper clBLAS or CPU BLAS comparison is not available for non-BLAS routines.
  static StatusCode RunReference1(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    return RunReference(args, buffers[0], queue);
  }

  static StatusCode RunReference2(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    return RunReference(args, buffers[0], queue);
  }

  // Describes how to download the results of the computation (more importantly: which buffer)
  static std::vector<T> DownloadResult(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    std::vector<T> result(args.b_size, static_cast<T>(0));
    buffers.b_mat.Read(queue, args.b_size, result);
    return result;
  }

  // Describes how to compute the indices of the result buffer
  static size_t ResultID1(const Arguments<T> &args) { return args.m; }
  static size_t ResultID2(const Arguments<T> &args) { return Ceil(args.n, args.m); }
  static size_t GetResultIndex(const Arguments<T> &args, const size_t id1, const size_t id2) {
    return id1 * Ceil(args.n, args.m) + id2;
  }

  // Describes how to compute performance metrics
  static size_t GetFlops(const Arguments<T> &args) {
    const auto block_size = args.m;
    const auto num_blocks = CeilDiv(args.n, block_size);
    return num_blocks * (block_size * (block_size / 2) * (block_size / 2));
  }
  static size_t GetBytes(const Arguments<T> &args) {
    return (args.a_size * args.b_size) * sizeof(T);
  }
};

// =================================================================================================
} // namespace clblast

// CLBLAST_TEST_ROUTINES_XINVERT_H_
#endif
<commit_msg>Small fix for a file that isn't currently compiled anymore<commit_after>
// =================================================================================================
// This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
// project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
// width of 100 characters per line.
//
// Author(s):
//   Cedric Nugteren <www.cedricnugteren.nl>
//
// This file implements a class with static methods to describe the Xinvert routine. Examples of
// such 'descriptions' are how to calculate the size a of buffer or how to run the routine. These
// static methods are used by the correctness tester and the performance tester.
//
// =================================================================================================

#ifndef CLBLAST_TEST_ROUTINES_XINVERT_H_
#define CLBLAST_TEST_ROUTINES_XINVERT_H_

#include <vector>
#include <string>

#include "utilities/utilities.hpp"

namespace clblast {
// =================================================================================================

template <typename T>
StatusCode RunReference(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
  const bool is_upper = ((args.triangle == Triangle::kUpper && args.layout != Layout::kRowMajor) ||
                         (args.triangle == Triangle::kLower && args.layout == Layout::kRowMajor));

  // Data transfer from OpenCL to std::vector
  std::vector<T> a_mat_cpu(args.a_size, T{0.0});
  buffers.a_mat.Read(queue, args.a_size, a_mat_cpu);

  // Creates the output buffer
  std::vector<T> b_mat_cpu(args.b_size, T{0.0});

  // Helper variables
  const auto block_size = args.m;
  const auto num_blocks = CeilDiv(args.n, block_size);
  const auto a_ld = args.a_ld;
  const auto b_ld = block_size;

  // Checks for valid arguments
  if ((block_size == 0) || (args.n == 0)) {
    return StatusCode::kInvalidDimension;
  }
  if ((block_size % 16 != 0) || (block_size > 128)) {
    return StatusCode::kUnknownError;
  }

  // Loops over the amount of diagonal blocks of size args.m by args.m each
  for (auto block_id = size_t{0}; block_id < num_blocks; ++block_id) {
    const auto a_offset = block_id * (block_size + a_ld * block_size) + args.a_offset;
    const auto b_offset = block_id * block_size * block_size;

    // Inverts the diagonal elements of the matrix
    for (auto i = size_t{0}; i < block_size; ++i) {
      auto a_value = T{1.0};
      if (args.diagonal == Diagonal::kNonUnit) {
        if (i + block_id * block_size < args.n) {
          if (a_mat_cpu[i * a_ld + i + a_offset] == T{0.0}) { return StatusCode::kUnknownError; }
          a_value = T{1.0} / a_mat_cpu[i * a_ld + i + a_offset];
        }
      }
      b_mat_cpu[i * b_ld + i + b_offset] = a_value;
    }

    // Inverts the upper triangle row by row
    if (is_upper) {
      for (int i = static_cast<int>(block_size) - 2; i >= 0; --i) {
        for (auto j = static_cast<int>(block_size) - 1; j > i; --j) {
          auto sum = T{0.0};
          for (auto k = i + 1; k <= j; ++k) {
            auto a_value = T{0.0};
            if ((i + block_id * block_size < args.n) && (k + block_id * block_size < args.n)) {
              a_value = a_mat_cpu[k * a_ld + i + a_offset];
            }
            sum += a_value * b_mat_cpu[j * b_ld + k + b_offset];
          }
          b_mat_cpu[j * b_ld + i + b_offset] = - sum * b_mat_cpu[i * b_ld + i + b_offset];
        }
      }
    }

    // Inverts the lower triangle row by row
    else {
      for (auto i = size_t{1}; i < block_size; ++i) {
        for (auto j = size_t{0}; j < i; ++j) {
          auto sum = T{0.0};
          for (auto k = j; k < i; ++k) {
            auto a_value = T{0.0};
            if ((i + block_id * block_size < args.n) && (k + block_id * block_size < args.n)) {
              a_value = a_mat_cpu[k * a_ld + i + a_offset];
            }
            sum += a_value * b_mat_cpu[j * b_ld + k + b_offset];
          }
          b_mat_cpu[j * b_ld + i + b_offset] = - sum * b_mat_cpu[i * b_ld + i + b_offset];
        }
      }
    }
  }

  // Data transfer back to OpenCL
  buffers.b_mat.Write(queue, args.b_size, b_mat_cpu);
  return StatusCode::kSuccess;
}

// Half-precision version calling the above reference implementation after conversions
template <>
StatusCode RunReference<half>(const Arguments<half> &args, Buffers<half> &buffers, Queue &queue) {
  auto a_buffer2 = HalfToFloatBuffer(buffers.a_mat, queue());
  auto b_buffer2 = HalfToFloatBuffer(buffers.b_mat, queue());
  auto dummy = clblast::Buffer<float>(0);
  auto buffers2 = Buffers<float>{dummy, dummy, a_buffer2, b_buffer2, dummy, dummy, dummy};
  auto args2 = Arguments<float>();
  args2.a_size = args.a_size; args2.b_size = args.b_size;
  args2.a_ld = args.a_ld; args2.m = args.m; args2.n = args.n;
  args2.a_offset = args.a_offset;
  args2.layout = args.layout; args2.triangle = args.triangle; args2.diagonal = args.diagonal;
  auto status = RunReference(args2, buffers2, queue);
  FloatToHalfBuffer(buffers.b_mat, b_buffer2, queue());
  return status;
}

// =================================================================================================

// See comment at top of file for a description of the class
template <typename T>
class TestXinvert {
 public:

  // The BLAS level: 4 for the extra routines
  static size_t BLASLevel() { return 4; }

  // The list of arguments relevant for this routine
  static std::vector<std::string> GetOptions() {
    return {kArgN, kArgM,
            kArgLayout, kArgTriangle, kArgDiagonal,
            kArgALeadDim, kArgAOffset};
  }

  // Describes how to obtain the sizes of the buffers
  static size_t GetSizeA(const Arguments<T> &args) {
    return args.n * args.a_ld + args.a_offset;
  }
  static size_t GetSizeB(const Arguments<T> &args) {
    const auto block_size = args.m;
    const auto num_blocks = CeilDiv(args.n, block_size);
    return num_blocks * block_size * block_size;
  }

  // Describes how to set the sizes of all the buffers
  static void SetSizes(Arguments<T> &args) {
    args.a_size = GetSizeA(args);
    args.b_size = GetSizeB(args);
  }

  // Describes what the default values of the leading dimensions of the matrices are
  static size_t DefaultLDA(const Arguments<T> &args) { return args.n; }
  static size_t DefaultLDB(const Arguments<T> &) { return 1; } // N/A for this routine
  static size_t DefaultLDC(const Arguments<T> &) { return 1; } // N/A for this routine

  // Describes which omatcopyose options are relevant for this routine
  using Transposes = std::vector<Transpose>;
  static Transposes GetATransposes(const Transposes &) { return {}; } // N/A for this routine
  static Transposes GetBTransposes(const Transposes &) { return {}; } // N/A for this routine

  // Describes how to prepare the input data
  static void PrepareData(const Arguments<T>&, Queue&, const int, std::vector<T>&,
                          std::vector<T>&, std::vector<T>&, std::vector<T>&, std::vector<T>&,
                          std::vector<T>&, std::vector<T>&) {} // N/A for this routine

  // Describes how to run the CLBlast routine
  static StatusCode RunRoutine(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    try {
      auto event = cl_event{};
      auto inverter = Xinvert<T>(queue, &event);
      inverter.InvertMatrixDiagonalBlocks(args.layout, args.triangle, args.diagonal,
                                          args.n, args.m,
                                          buffers.a_mat, args.a_offset, args.a_ld,
                                          buffers.b_mat);
      clWaitForEvents(1, &event);
      clReleaseEvent(event);
    } catch (...) { return DispatchException(); }
    return StatusCode::kSuccess;
  }

  // Describes how to run a naive version of the routine (for correctness/performance comparison).
  // Note that a proper clBLAS or CPU BLAS comparison is not available for non-BLAS routines.
  static StatusCode RunReference1(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    return RunReference(args, buffers, queue);
  }

  static StatusCode RunReference2(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    return RunReference(args, buffers, queue);
  }

  // Describes how to download the results of the computation (more importantly: which buffer)
  static std::vector<T> DownloadResult(const Arguments<T> &args, Buffers<T> &buffers, Queue &queue) {
    std::vector<T> result(args.b_size, static_cast<T>(0));
    buffers.b_mat.Read(queue, args.b_size, result);
    return result;
  }

  // Describes how to compute the indices of the result buffer
  static size_t ResultID1(const Arguments<T> &args) { return args.m; }
  static size_t ResultID2(const Arguments<T> &args) { return Ceil(args.n, args.m); }
  static size_t GetResultIndex(const Arguments<T> &args, const size_t id1, const size_t id2) {
    return id1 * Ceil(args.n, args.m) + id2;
  }

  // Describes how to compute performance metrics
  static size_t GetFlops(const Arguments<T> &args) {
    const auto block_size = args.m;
    const auto num_blocks = CeilDiv(args.n, block_size);
    return num_blocks * (block_size * (block_size / 2) * (block_size / 2));
  }
  static size_t GetBytes(const Arguments<T> &args) {
    return (args.a_size * args.b_size) * sizeof(T);
  }
};

// =================================================================================================
} // namespace clblast

// CLBLAST_TEST_ROUTINES_XINVERT_H_
#endif
<|endoftext|>


<commit_before>#ifndef CTHREADRINGBUF
#define CTHREADRINGBUF
#include<condition_variable>
#include<memory>	//allocator
#include<mutex>
#include<queue>
#include<utility>	//forward, move, move_if_noexcept, pair
#include"CAtomic_stack.hpp"
#include"../algorithm/algorithm.hpp"	//for_each_val

namespace nThread
{
	//a fixed-sized and cannot overwrite when buffer is full
	template<class T>
	class CThreadRingBuf
	{
	public:
		using allocator_type=std::allocator<T>;
		using size_type=typename std::allocator<T>::size_type;
		using value_type=T;
	private:
		using pointer=typename std::allocator<T>::pointer;
		static allocator_type alloc_;
		const pointer begin_;
		const size_type size_;
		std::mutex mut_;
		std::queue<pointer> queue_;
		std::condition_variable read_cv_;
		CAtomic_stack<std::pair<bool,pointer>> stack_;
	public:
		explicit CThreadRingBuf(const size_type size)
			:begin_{alloc_.allocate(size)},size_{size}
		{
			nAlgorithm::for_each_val(begin_,begin_+size,[this](const auto p){
				stack_.emplace_not_ts(false,p);
			});
		}
		inline bool empty() const noexcept
		{
			return queue_.empty();
		}
		inline size_type available() const noexcept
		{
			return static_cast<size_type>(queue_.size());
		}
		//if constructor or assignment operator you use here is not noexcept, it may not be exception safety
		value_type wait_and_read()
		{
			typename CAtomic_stack<std::pair<bool,pointer>>::CNode node;
			std::unique_lock<std::mutex> lock{mut_};
			read_cv_.wait(lock,[this]() noexcept{return available();});
			const pointer p{queue_.front()};
			//1. if move constructor is noexcept, it is exception safety
			//2. if move constructor is not noexcept and copy constructor exists, it is exception safety
			//3. if move constructor is not noexcept and copy constructor does not exist, it may not be exception safety
			const auto temp{std::move_if_noexcept(*p)};
			queue_.pop();
			lock.unlock();
			node.get_data()=std::make_pair(true,std::move(p));
			stack_.emplace_CNode(std::move(node));
			return temp;
		}
		inline size_type size() const noexcept
		{
			return size_;
		}
		//can only be used when your write will not overwrite the data
		template<class ... Args>
		void write_and_notify(Args &&...args)
		{
			typename CAtomic_stack<std::pair<bool,pointer>>::CNode node;
			std::pair<bool,pointer> p{stack_.pop()};
			if(p.first)
			{
				alloc_.destroy(p.second);
				p.first=false;
			}
			try
			{
				alloc_.construct(p.second,std::forward<decltype(args)>(args)...);
			}catch(...)
			{
				node.get_data()=std::move(p);
				stack_.emplace_CNode(std::move(node));
				throw ;
			}
			std::lock_guard<std::mutex> lock{mut_};
			queue_.emplace(p.second);
			if(queue_.size()==1)
				read_cv_.notify_all();
		}
		~CThreadRingBuf()
		{
			while(!stack_.empty())
			{
				const std::pair<bool,pointer> p{stack_.pop()};
				if(p.first)
					alloc_.destroy(p.second);
			}
			while(available())
			{
				alloc_.destroy(queue_.front());
				queue_.pop();
			}
			alloc_.deallocate(begin_,size());
		}
	};

	template<class T>
	typename CThreadRingBuf<T>::allocator_type CThreadRingBuf<T>::alloc_;
}

#endif<commit_msg>update<commit_after>#ifndef CTHREADRINGBUF
#define CTHREADRINGBUF
#include<condition_variable>
#include<memory>	//allocator
#include<mutex>
#include<queue>
#include<type_traits>
#include<utility>	//forward, move, move_if_noexcept, pair
#include"CAtomic_stack.hpp"
#include"../algorithm/algorithm.hpp"	//for_each_val

namespace nThread
{
	//a fixed-sized and cannot overwrite when buffer is full
	template<class T>
	class CThreadRingBuf
	{
	public:
		using allocator_type=std::allocator<T>;
		using size_type=typename allocator_type::size_type;
		using value_type=T;
	private:
		using pointer=typename allocator_type::pointer;
		static allocator_type alloc_;
		const pointer begin_;
		const size_type size_;
		std::mutex mut_;
		std::queue<pointer> queue_;
		std::condition_variable read_cv_;
		CAtomic_stack<std::pair<bool,pointer>> stack_;
		pointer pop_and_destroy_() noexcept
		{
			std::pair<bool,pointer> p{stack_.pop()};
			if(p.first)
				alloc_.destroy(p.second);
			return p.second;
		}
		template<class ... Args>
		pointer write_(std::true_type,Args &&...args) noexcept
		{
			const pointer p{pop_and_destroy_()};
			alloc_.construct(p,std::forward<decltype(args)>(args)...);
			return p;
		}
		template<class ... Args>
		pointer write_(std::false_type,Args &&...args)
		{
			typename CAtomic_stack<std::pair<bool,pointer>>::CNode node;
			const pointer p{pop_and_destroy_()};
			try
			{
				alloc_.construct(p,std::forward<decltype(args)>(args)...);
			}catch(...)
			{
				stack_.emplace(std::move(node),false,p);
				throw ;
			}
			return p;
		}
		void write_and_notify_queue_(const pointer p)
		{
			std::lock_guard<std::mutex> lock{mut_};
			queue_.emplace(p);
			if(queue_.size()==1)
				read_cv_.notify_all();
		}
		void write_queue_(const pointer p)
		{
			std::lock_guard<std::mutex> lock{mut_};
			queue_.emplace(p);
		}
	public:
		explicit CThreadRingBuf(const size_type size)
			:begin_{alloc_.allocate(size)},size_{size}
		{
			nAlgorithm::for_each_val(begin_,begin_+size,[this](const auto p){
				stack_.emplace_not_ts(false,p);
			});
		}
		inline size_type available() const noexcept
		{
			return static_cast<size_type>(queue_.size());
		}
		inline bool empty() const noexcept
		{
			return queue_.empty();
		}
		inline size_type size() const noexcept
		{
			return size_;
		}
		//if constructor or assignment operator you use here is not noexcept, it may not be exception safety
		value_type read()
		{
			typename CAtomic_stack<std::pair<bool,pointer>>::CNode node;
			std::lock_guard<std::mutex> lock{mut_};
			const pointer p{queue_.front()};
			const auto temp{std::move_if_noexcept(*p)};
			queue_.pop();
			lock.unlock();
			stack_.emplace(std::move(node),true,p);
			return temp;
		}
		//if constructor or assignment operator you use here is not noexcept, it may not be exception safety
		value_type wait_and_read()
		{
			typename CAtomic_stack<std::pair<bool,pointer>>::CNode node;
			std::unique_lock<std::mutex> lock{mut_};
			read_cv_.wait(lock,[this]() noexcept{return available();});
			const pointer p{queue_.front()};
			const auto temp{std::move_if_noexcept(*p)};
			queue_.pop();
			lock.unlock();
			stack_.emplace(std::move(node),true,p);
			return temp;
		}
		//can only be used when your write will not overwrite the data
		template<class ... Args>
		inline void write(Args &&...args)
		{
			write_queue_(write_(std::is_nothrow_constructible<value_type,Args...>{},std::forward<decltype(args)>(args)...));
		}
		//can only be used when your write will not overwrite the data
		template<class ... Args>
		inline void write_and_notify(Args &&...args)
		{
			write_and_notify_queue_(write_(std::is_nothrow_constructible<value_type,Args...>{},std::forward<decltype(args)>(args)...));
		}
		~CThreadRingBuf()
		{
			while(!stack_.empty())
			{
				const std::pair<bool,pointer> p{stack_.pop()};
				if(p.first)
					alloc_.destroy(p.second);
			}
			while(available())
			{
				alloc_.destroy(queue_.front());
				queue_.pop();
			}
			alloc_.deallocate(begin_,size());
		}
	};

	template<class T>
	typename CThreadRingBuf<T>::allocator_type CThreadRingBuf<T>::alloc_;
}

#endif<|endoftext|>


<commit_before>/----------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003, 2004, 2005, 2007 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------------------------------------------------

// test output of curved cells at the boundary and in the inner of the domain,
// where the last one is only relevant for mappings of type MappingQEulerian

#include "../tests.h"

#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <lac/full_matrix.h>
#include <lac/identity_matrix.h>
#include <base/quadrature_lib.h>
#include <base/thread_management.h>
#include <lac/vector.h>
#include <lac/vector_memory.h>
#include <lac/filtered_matrix.h>
#include <lac/precondition.h>
#include <lac/solver_cg.h>
#include <lac/sparse_matrix.h>
#include <grid/grid_generator.h>
#include <grid/grid_reordering.h>
#include <grid/grid_tools.h>
#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <dofs/dof_handler.h>
#include <dofs/dof_accessor.h>
#include <dofs/dof_tools.h>
#include <dofs/dof_constraints.h>
#include <fe/mapping_q1.h>
#include <fe/mapping_q_eulerian.h>
#include <fe/fe_q.h>
#include <fe/fe_system.h>
#include <numerics/matrices.h>
#include <numerics/data_out.h>
#include <base/multithread_info.h>
#include <fstream>
#include <cmath>
#include <iostream>
#include <vector>
using namespace dealii;

// this is copied from GridGenerator
void laplace_solve (const SparseMatrix<double> &S,
		    const std::map<unsigned int,double> &m,
		    Vector<double> &u)
{
  const unsigned int n_dofs=S.n();
  FilteredMatrix<Vector<double> > SF (S);
  PreconditionJacobi<SparseMatrix<double> > prec;
  prec.initialize(S, 1.2);
  FilteredMatrix<Vector<double> > PF (prec);

  SolverControl control (10000, 1.e-10, false, false);
  GrowingVectorMemory<Vector<double> > mem;
  SolverCG<Vector<double> > solver (control, mem);

  Vector<double> f(n_dofs);

  SF.add_constraints(m);
  SF.apply_constraints (f, true);
  solver.solve(SF, u, f, PF);
}

// create a rinf grid and compute a MappingQEuler to represent the inner
// boundary
void curved_grid (std::ofstream &out)
{
				   // number of cells in radial and
				   // circumferential direction
  const unsigned int n_phi=4,
		       n_r=8;
				   // inner and outer radius
  const double r_i=0.5,
	       r_a=2.0;
				   // we want to increase the radial extent of
				   // each cell by 'factor'. compute, how large
				   // the first extent 'dr' has to be
  double factor=2.,
	    sum=0;
  for (unsigned int j=0; j<n_r; ++j)
    sum+=std::pow(factor,1.*j);
  double dr=(r_a-r_i)/sum;
				   // radii of the cells
  std::vector<double> r(n_r+1,r_i);
  for (unsigned int j=1; j<n_r+1; ++j)
    {
      r[j]=r[j-1]+dr;
      dr*=factor;
    }
				   // create vertices
  std::vector<Point<2> > vertices(n_phi*(n_r+1));
  for (unsigned int j=0; j<n_r+1; ++j)
    for (unsigned int i=0; i<n_phi; ++i)
      {
	const unsigned int p=i+j*n_phi;
	const double alpha=i*2*numbers::PI/n_phi;
	vertices[p]=Point<2>(r[j]*cos(alpha),r[j]*sin(alpha));
      }
				   // create connectivity
  std::vector<CellData<2> > cells(n_phi*n_r);
  for (unsigned int j=0; j<n_r; ++j)
    for (unsigned int i=0; i<n_phi; ++i)
      {
	const unsigned int index=i+j*n_phi;
	const unsigned int p            =i          +    j*n_phi;
	const unsigned int p_iplus      =(i+1)%n_phi+    j*n_phi;
	const unsigned int p_iplus_jplus=(i+1)%n_phi+(j+1)*n_phi;
	const unsigned int p_jplus      =i          +(j+1)*n_phi;

	cells[index].vertices[0]=p_iplus;
	cells[index].vertices[1]=p;
	cells[index].vertices[2]=p_jplus;
	cells[index].vertices[3]=p_iplus_jplus;
      }
				   // create triangulation
  Triangulation<2> triangulation;
  triangulation.create_triangulation_compatibility(vertices,cells,SubCellData());
				   // now provide everything that is
				   // needed for solving a Laplace
				   // equation.
  MappingQ1<2> mapping_q1;
  FE_Q<2> fe(2);
  DoFHandler<2> dof_handler(triangulation);
  dof_handler.distribute_dofs(fe);
  SparsityPattern sparsity_pattern (dof_handler.n_dofs (), dof_handler.n_dofs (),
				    dof_handler.max_couplings_between_dofs());
  DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
  sparsity_pattern.compress ();
  SparseMatrix<double> S(sparsity_pattern);
  QGauss4<2> quadrature;
  MatrixCreator::create_laplace_matrix(mapping_q1, dof_handler, quadrature, S);
				   // set up the boundary values for
				   // the laplace problem
  std::vector<std::map<unsigned int,double> > m(2);
				   // fill these maps: on the inner boundary try
				   // to approximate a circle, on the outer
				   // boundary use straight lines
  DoFHandler<2>::cell_iterator cell=dof_handler.begin_active(),
					  endc=dof_handler.end();
  DoFHandler<2>::face_iterator face;
  for (; cell!=endc; ++cell)
    {
				       // fix all vertices
      for (unsigned int vertex_no=0;
	   vertex_no<GeometryInfo<2>::vertices_per_cell; ++vertex_no)
	{
	  for (unsigned int i=0; i<2; ++i)
	    m[i][cell->vertex_dof_index(vertex_no, 0)]=0.;
	}

      if (cell->at_boundary())
	for (unsigned int face_no=0; face_no<GeometryInfo<2>::faces_per_cell; ++face_no)
	  {
	    face=cell->face(face_no);
						 // insert a modifiued value for
						 // the middle point of boundary
						 // faces
	    if (face->at_boundary())
	      {
		const double eps=1e-4;
		if (std::fabs(face->vertex(1).norm()-r_i)<eps)
		    for (unsigned int i=0; i<2; ++i)
		      m[i][face->dof_index(0)]= (face->center()*(r_i/face->center().norm()-1))(i);
 		else if (std::fabs(face->vertex(1).norm()-r_a)<eps)
 		    for (unsigned int i=0; i<2; ++i)
 		      m[i][face->dof_index(0)]=0.;
 		else
 		  Assert(false, ExcInternalError());
	      }
	  }
    }
				   // solve the 2 problems with
				   // different right hand sides.
  Vector<double> us[2];
  for (unsigned int i=0; i<2; ++i)
    us[i].reinit (dof_handler.n_dofs());
				   // solve linear systems in parallel
  Threads::ThreadGroup<> threads;
  for (unsigned int i=0; i<2; ++i)
    threads += Threads::spawn (&laplace_solve)(S, m[i], us[i]);
  threads.join_all ();
				   // create a new DoFHandler for the combined
				   // system
  FESystem<2> cfe(FE_Q<2>(2),2);
  DoFHandler<2> cdh(triangulation);
  cdh.distribute_dofs(cfe);
  Vector<double> displacements(cdh.n_dofs()),
    dx(fe.dofs_per_cell),
    dy(fe.dofs_per_cell),
    dxy(cfe.dofs_per_cell);
  DoFHandler<2>::active_cell_iterator component_cell=dof_handler.begin_active(),
						end_c=dof_handler.end(),
				       combined_cell=cdh.begin_active();
  for (; component_cell!=end_c; ++component_cell, ++combined_cell)
    {
      component_cell->get_dof_values (us[0], dx);
      component_cell->get_dof_values (us[1], dy);
      for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
	{
	  dxy(cfe.component_to_system_index(0,i))= dx(i);
	  dxy(cfe.component_to_system_index(1,i))= dy(i);
	}
      combined_cell->set_dof_values (dxy, displacements);
    }
				   // and create the MappingQEulerian
  MappingQEulerian<2> euler(2, displacements, cdh);
				   // now the actual test
  DataOut<2> data_out;
  data_out.attach_dof_handler(cdh);
  std::vector<std::string> names;
  names.push_back("x_displacement");
  names.push_back("y_displacement");
  data_out.add_data_vector(displacements,names);
				   // output with no mapping
  data_out.build_patches(5);
  data_out.write_gnuplot(out);
				   // output with no curved cells
  data_out.build_patches(euler,5,multithread_info.n_default_threads,DataOut<2>::no_curved_cells);
  data_out.write_gnuplot(out);
  				   // output with curved cells at the boundary
  				   // (default)
  data_out.build_patches(euler,5);
  data_out.write_gnuplot(out);
  				   // output with all cells curved
  data_out.build_patches(euler,5,multithread_info.n_default_threads,DataOut<2>::curved_inner_cells);
  data_out.write_gnuplot(out);
}

int main ()
{
  std::ofstream logfile("data_out_curved_cells/output");
  deallog.attach(logfile);
  deallog << std::setprecision (4);
  logfile << std::setprecision (4);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  curved_grid (logfile);
}

<commit_msg>Fix testcase for good this time.<commit_after>//----------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2003, 2004, 2005, 2007 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------------------------------------------------

// test output of curved cells at the boundary and in the inner of the domain,
// where the last one is only relevant for mappings of type MappingQEulerian

#include "../tests.h"

#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <lac/full_matrix.h>
#include <lac/identity_matrix.h>
#include <base/quadrature_lib.h>
#include <base/thread_management.h>
#include <lac/vector.h>
#include <lac/vector_memory.h>
#include <lac/filtered_matrix.h>
#include <lac/precondition.h>
#include <lac/solver_cg.h>
#include <lac/sparse_matrix.h>
#include <grid/grid_generator.h>
#include <grid/grid_reordering.h>
#include <grid/grid_tools.h>
#include <grid/tria.h>
#include <grid/tria_accessor.h>
#include <grid/tria_iterator.h>
#include <dofs/dof_handler.h>
#include <dofs/dof_accessor.h>
#include <dofs/dof_tools.h>
#include <dofs/dof_constraints.h>
#include <fe/mapping_q1.h>
#include <fe/mapping_q_eulerian.h>
#include <fe/fe_q.h>
#include <fe/fe_system.h>
#include <numerics/matrices.h>
#include <numerics/data_out.h>
#include <base/multithread_info.h>
#include <fstream>
#include <cmath>
#include <iostream>
#include <vector>
using namespace dealii;

// this is copied from GridGenerator
void laplace_solve (const SparseMatrix<double> &S,
		    const std::map<unsigned int,double> &m,
		    Vector<double> &u)
{
  const unsigned int n_dofs=S.n();
  FilteredMatrix<Vector<double> > SF (S);
  PreconditionJacobi<SparseMatrix<double> > prec;
  prec.initialize(S, 1.2);
  FilteredMatrix<Vector<double> > PF (prec);

  SolverControl control (10000, 1.e-10, false, false);
  GrowingVectorMemory<Vector<double> > mem;
  SolverCG<Vector<double> > solver (control, mem);

  Vector<double> f(n_dofs);

  SF.add_constraints(m);
  SF.apply_constraints (f, true);
  solver.solve(SF, u, f, PF);
}

// create a rinf grid and compute a MappingQEuler to represent the inner
// boundary
void curved_grid (std::ofstream &out)
{
				   // number of cells in radial and
				   // circumferential direction
  const unsigned int n_phi=4,
		       n_r=8;
				   // inner and outer radius
  const double r_i=0.5,
	       r_a=2.0;
				   // we want to increase the radial extent of
				   // each cell by 'factor'. compute, how large
				   // the first extent 'dr' has to be
  double factor=2.,
	    sum=0;
  for (unsigned int j=0; j<n_r; ++j)
    sum+=std::pow(factor,1.*j);
  double dr=(r_a-r_i)/sum;
				   // radii of the cells
  std::vector<double> r(n_r+1,r_i);
  for (unsigned int j=1; j<n_r+1; ++j)
    {
      r[j]=r[j-1]+dr;
      dr*=factor;
    }
				   // create vertices
  std::vector<Point<2> > vertices(n_phi*(n_r+1));
  for (unsigned int j=0; j<n_r+1; ++j)
    for (unsigned int i=0; i<n_phi; ++i)
      {
	const unsigned int p=i+j*n_phi;
	const double alpha=i*2*numbers::PI/n_phi;
	vertices[p]=Point<2>(r[j]*cos(alpha),r[j]*sin(alpha));
      }
				   // create connectivity
  std::vector<CellData<2> > cells(n_phi*n_r);
  for (unsigned int j=0; j<n_r; ++j)
    for (unsigned int i=0; i<n_phi; ++i)
      {
	const unsigned int index=i+j*n_phi;
	const unsigned int p            =i          +    j*n_phi;
	const unsigned int p_iplus      =(i+1)%n_phi+    j*n_phi;
	const unsigned int p_iplus_jplus=(i+1)%n_phi+(j+1)*n_phi;
	const unsigned int p_jplus      =i          +(j+1)*n_phi;

	cells[index].vertices[0]=p_iplus;
	cells[index].vertices[1]=p;
	cells[index].vertices[2]=p_jplus;
	cells[index].vertices[3]=p_iplus_jplus;
      }
				   // create triangulation
  Triangulation<2> triangulation;
  triangulation.create_triangulation_compatibility(vertices,cells,SubCellData());
				   // now provide everything that is
				   // needed for solving a Laplace
				   // equation.
  MappingQ1<2> mapping_q1;
  FE_Q<2> fe(2);
  DoFHandler<2> dof_handler(triangulation);
  dof_handler.distribute_dofs(fe);
  SparsityPattern sparsity_pattern (dof_handler.n_dofs (), dof_handler.n_dofs (),
				    dof_handler.max_couplings_between_dofs());
  DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
  sparsity_pattern.compress ();
  SparseMatrix<double> S(sparsity_pattern);
  QGauss4<2> quadrature;
  MatrixCreator::create_laplace_matrix(mapping_q1, dof_handler, quadrature, S);
				   // set up the boundary values for
				   // the laplace problem
  std::vector<std::map<unsigned int,double> > m(2);
				   // fill these maps: on the inner boundary try
				   // to approximate a circle, on the outer
				   // boundary use straight lines
  DoFHandler<2>::cell_iterator cell=dof_handler.begin_active(),
					  endc=dof_handler.end();
  DoFHandler<2>::face_iterator face;
  for (; cell!=endc; ++cell)
    {
				       // fix all vertices
      for (unsigned int vertex_no=0;
	   vertex_no<GeometryInfo<2>::vertices_per_cell; ++vertex_no)
	{
	  for (unsigned int i=0; i<2; ++i)
	    m[i][cell->vertex_dof_index(vertex_no, 0)]=0.;
	}

      if (cell->at_boundary())
	for (unsigned int face_no=0; face_no<GeometryInfo<2>::faces_per_cell; ++face_no)
	  {
	    face=cell->face(face_no);
						 // insert a modifiued value for
						 // the middle point of boundary
						 // faces
	    if (face->at_boundary())
	      {
		const double eps=1e-4;
		if (std::fabs(face->vertex(1).norm()-r_i)<eps)
		    for (unsigned int i=0; i<2; ++i)
		      m[i][face->dof_index(0)]= (face->center()*(r_i/face->center().norm()-1))(i);
 		else if (std::fabs(face->vertex(1).norm()-r_a)<eps)
 		    for (unsigned int i=0; i<2; ++i)
 		      m[i][face->dof_index(0)]=0.;
 		else
 		  Assert(false, ExcInternalError());
	      }
	  }
    }
				   // solve the 2 problems with
				   // different right hand sides.
  Vector<double> us[2];
  for (unsigned int i=0; i<2; ++i)
    us[i].reinit (dof_handler.n_dofs());
				   // solve linear systems in parallel
  Threads::ThreadGroup<> threads;
  for (unsigned int i=0; i<2; ++i)
    threads += Threads::spawn (&laplace_solve)(S, m[i], us[i]);
  threads.join_all ();
				   // create a new DoFHandler for the combined
				   // system
  FESystem<2> cfe(FE_Q<2>(2),2);
  DoFHandler<2> cdh(triangulation);
  cdh.distribute_dofs(cfe);
  Vector<double> displacements(cdh.n_dofs()),
    dx(fe.dofs_per_cell),
    dy(fe.dofs_per_cell),
    dxy(cfe.dofs_per_cell);
  DoFHandler<2>::active_cell_iterator component_cell=dof_handler.begin_active(),
						end_c=dof_handler.end(),
				       combined_cell=cdh.begin_active();
  for (; component_cell!=end_c; ++component_cell, ++combined_cell)
    {
      component_cell->get_dof_values (us[0], dx);
      component_cell->get_dof_values (us[1], dy);
      for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
	{
	  dxy(cfe.component_to_system_index(0,i))= dx(i);
	  dxy(cfe.component_to_system_index(1,i))= dy(i);
	}
      combined_cell->set_dof_values (dxy, displacements);
    }
				   // and create the MappingQEulerian
  MappingQEulerian<2> euler(2, displacements, cdh);
				   // now the actual test
  DataOut<2> data_out;
  data_out.attach_dof_handler(cdh);
  std::vector<std::string> names;
  names.push_back("x_displacement");
  names.push_back("y_displacement");
  data_out.add_data_vector(displacements,names);
				   // output with no mapping
  data_out.build_patches(5);
  data_out.write_gnuplot(out);
				   // output with no curved cells
  data_out.build_patches(euler,5,DataOut<2>::no_curved_cells);
  data_out.write_gnuplot(out);
  				   // output with curved cells at the boundary
  				   // (default)
  data_out.build_patches(euler,5);
  data_out.write_gnuplot(out);
  				   // output with all cells curved
  data_out.build_patches(euler,5,DataOut<2>::curved_inner_cells);
  data_out.write_gnuplot(out);
}

int main ()
{
  std::ofstream logfile("data_out_curved_cells/output");
  deallog.attach(logfile);
  deallog << std::setprecision (4);
  logfile << std::setprecision (4);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  curved_grid (logfile);
}

<|endoftext|>


<commit_before>/*
 * CampSiteActiveAreaImplementation.cpp
 *
 *  Created on: Jan 1, 2012
 *      Author: Kyle
 */

#include "server/zone/objects/area/CampSiteActiveArea.h"
#include "server/zone/objects/area/CampSiteObserver.h"
#include "server/zone/objects/structure/StructureObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/managers/structure/StructureManager.h"
#include "server/zone/objects/tangible/terminal/Terminal.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/area/events/CampAbandonTask.h"
#include "server/zone/objects/area/events/CampDespawnTask.h"

void CampSiteActiveAreaImplementation::initializeTransientMembers() {
	startTasks();
}

void CampSiteActiveAreaImplementation::init(CampStructureTemplate* campData) {
	campStructureData = campData;
	setRadius(campStructureData->getRadius());
	startTasks();
}

void CampSiteActiveAreaImplementation::startTasks() {
	Locker locker(&taskMutex);

	if(despawnTask == NULL) {
		despawnTask = new CampDespawnTask(_this.get());
	} else {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
	}

	if(abandonTask == NULL) {
		abandonTask = new CampAbandonTask(_this.get());
	} else {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
	}

	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);
	abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);

}

void CampSiteActiveAreaImplementation::notifyEnter(SceneObject* object) {
	if (!object->isPlayerCreature())
		return;

	if (camp == NULL || terminal == NULL)
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	if (camp != NULL)
		camp->addTemplateSkillMods(player);

	if (campObserver == NULL) {
		campObserver = new CampSiteObserver(_this.get());
		campObserver->deploy();
	}

	if(object == campOwner && !abandoned) {

		Locker locker(&taskMutex);

		if(abandonTask != NULL && abandonTask->isScheduled())
			abandonTask->cancel();

		object->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	} else {

		StringIdChatParameter stringID("camp", "prose_camp_enter");
		stringID.setTO(terminal->getDisplayedName());
		player->sendSystemMessage(stringID);

		player->sendSystemMessage("@camp:sys_camp_heal"); // While in the camp, medics and entertainers can heal your wounds.

	}

	if (object->isPlayerCreature() && !visitors.contains(object->getObjectID()))
		visitors.add(object->getObjectID());

	if (object->isPlayerCreature())
		object->registerObserver(ObserverEventType::HEALINGPERFORMED, campObserver);
}

void CampSiteActiveAreaImplementation::notifyExit(SceneObject* object) {
	object->dropObserver(ObserverEventType::HEALINGPERFORMED, campObserver);

	if (!object->isPlayerCreature())
		return;

	if (camp == NULL || terminal == NULL)
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	if (camp != NULL)
		camp->removeTemplateSkillMods(player);

	if(abandoned || object != campOwner) {
		StringIdChatParameter stringID("camp", "prose_camp_exit");
		stringID.setTO(terminal->getDisplayedName());
		player->sendSystemMessage(stringID);
		return;
	}

	Locker locker(&taskMutex);

	if(!abandoned && abandonTask != NULL && !abandonTask->isScheduled()) {
		try {
			abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);
		} catch (Exception& e) {

		}
	}
}

int CampSiteActiveAreaImplementation::notifyHealEvent(int64 quantity) {
	// Increase XP Pool for heals
	currentXp += (campStructureData->getExperience() / 180);
	return 1;
}

int CampSiteActiveAreaImplementation::notifyCombatEvent() {
	abandonCamp();

	Locker locker(&taskMutex);

	if(abandonTask != NULL)
		if(abandonTask->isScheduled())
			abandonTask->cancel();

	if(campOwner != NULL)
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp"); // Your camp has been abandoned.

	return 1;
}

void CampSiteActiveAreaImplementation::abandonCamp() {
	abandoned = true;

	currentXp = 0;

	Locker locker(&taskMutex);

	if(despawnTask != NULL && despawnTask->isScheduled()) {
		despawnTask->cancel();
		int newTime = (CampSiteActiveArea::DESPAWNTIME / 6);
		int maxTime = CampSiteActiveArea::DESPAWNTIME - ((System::getTime() - timeCreated) * 1000);

		despawnTask->schedule(newTime < maxTime ? newTime : maxTime);
	}

	if(terminal != NULL)
		terminal->setCustomObjectName("Abandoned Camp", true);

	if(campOwner != NULL) {
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp"); // Your camp has been abandoned.
	}
}

bool CampSiteActiveAreaImplementation::despawnCamp() {
	Locker locker(_this.get());

	if(!abandoned && campOwner != NULL && campOwner->getZoneServer() != NULL) {
		/// Get Player Manager
		PlayerManager* playerManager = campOwner->getZoneServer()->getPlayerManager();
		if (playerManager == NULL) {
			error("playerManager is null");
			return false;
		}

		float durationUsed = ((float)(System::getTime() - timeCreated)) / (campStructureData->getDuration() / 4);
		if (durationUsed > 1)
			durationUsed = 1;

		int amount = 0;
		int campXp = campStructureData->getExperience();
		amount = (int)(campXp * durationUsed);

		amount += (int)((visitors.size() -1) * (campXp / 30) * durationUsed);
		amount += (int)(currentXp * durationUsed);

		playerManager->awardExperience(campOwner, "camp", amount, true);
	}

	Locker tlocker(&taskMutex);

	if(despawnTask != NULL ) {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
		despawnTask = NULL;
	}

	if(abandonTask != NULL) {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
		abandonTask = NULL;
	}

	tlocker.release();

	if(campOwner != NULL)
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if (camp != NULL) {
		if(camp->getZone() == NULL)
			return false;

		StructureManager::instance()->destroyStructure(camp);
	}

	destroyObjectFromWorld(true);
	destroyObjectFromDatabase(true);

	return true;
}

void CampSiteActiveAreaImplementation::assumeOwnership(CreatureObject* player) {
	if (camp == NULL || player == NULL)
		return;

	if (player->getSkillMod("camp") < campStructureData->getSkillRequired()) {
		player->sendSystemMessage("@camp:error_too_big"); // You cannot assume ownership of this camp. You lack the skill to maintain a camp of this size.
		return;
	}

	PlayerObject* playerGhost = player->getPlayerObject();

	if (playerGhost == NULL)
		return;

	for (int i = 0; i < playerGhost->getTotalOwnedStructureCount(); ++i) {
		uint64 oid = playerGhost->getOwnedStructure(i);

		ManagedReference<StructureObject*> structure = playerGhost->getZoneServer()->getObject(oid).castTo<StructureObject*>();

		if (structure->isCampStructure()) {
			player->sendSystemMessage("@camp:sys_already_camping"); // But you already have a camp established elsewhere!
			return;
		}
	}

	PlayerObject* ownerGhost = campOwner->getPlayerObject();

	if (ownerGhost != NULL) {
		ownerGhost->removeOwnedStructure(camp);
	}

	setOwner(player);

	abandoned = false;
	currentXp = 0;
	visitors.removeAll();

	Reference<SortedVector<ManagedReference<QuadTreeEntry*> >*> closeObjects = new SortedVector<ManagedReference<QuadTreeEntry*> >();
	zone->getInRangeObjects(camp->getWorldPositionX(), camp->getWorldPositionY(), campStructureData->getRadius(), closeObjects, true);

	for (int i = 0; i < closeObjects->size(); ++i) {
		SceneObject* scno = cast<SceneObject*>(closeObjects->get(i).get());
		if (scno->isPlayerCreature())
			visitors.add(scno->getObjectID());
	}

	playerGhost->addOwnedStructure(camp);

	campOwner->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	Locker locker(&taskMutex);

	if(abandonTask != NULL && abandonTask->isScheduled())
		abandonTask->cancel();

	if(despawnTask != NULL && despawnTask->isScheduled())
		despawnTask->cancel();

	timeCreated = System::getTime();
	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);

	if(terminal != NULL) {
		String campName = campOwner->getFirstName();
		if(!campOwner->getLastName().isEmpty())
			campName += " " + campOwner->getLastName();
		campName += "'s Camp";
		terminal->setCustomObjectName(campName, true);
	}

	player->sendSystemMessage("@camp:assuming_ownership"); //You assume ownership of the camp.
}
<commit_msg>[Fixed] players to receive system messages when entering/exiting their own camp - mantis 2083<commit_after>/*
 * CampSiteActiveAreaImplementation.cpp
 *
 *  Created on: Jan 1, 2012
 *      Author: Kyle
 */

#include "server/zone/objects/area/CampSiteActiveArea.h"
#include "server/zone/objects/area/CampSiteObserver.h"
#include "server/zone/objects/structure/StructureObject.h"
#include "server/zone/managers/player/PlayerManager.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/managers/structure/StructureManager.h"
#include "server/zone/objects/tangible/terminal/Terminal.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/area/events/CampAbandonTask.h"
#include "server/zone/objects/area/events/CampDespawnTask.h"

void CampSiteActiveAreaImplementation::initializeTransientMembers() {
	startTasks();
}

void CampSiteActiveAreaImplementation::init(CampStructureTemplate* campData) {
	campStructureData = campData;
	setRadius(campStructureData->getRadius());
	startTasks();
}

void CampSiteActiveAreaImplementation::startTasks() {
	Locker locker(&taskMutex);

	if(despawnTask == NULL) {
		despawnTask = new CampDespawnTask(_this.get());
	} else {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
	}

	if(abandonTask == NULL) {
		abandonTask = new CampAbandonTask(_this.get());
	} else {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
	}

	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);
	abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);

}

void CampSiteActiveAreaImplementation::notifyEnter(SceneObject* object) {
	if (!object->isPlayerCreature())
		return;

	if (camp == NULL || terminal == NULL)
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	if (camp != NULL)
		camp->addTemplateSkillMods(player);

	if (campObserver == NULL) {
		campObserver = new CampSiteObserver(_this.get());
		campObserver->deploy();
	}

	if(object == campOwner && !abandoned) {

		Locker locker(&taskMutex);

		if(abandonTask != NULL && abandonTask->isScheduled())
			abandonTask->cancel();

		object->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	}

	StringIdChatParameter stringID("camp", "prose_camp_enter");
	stringID.setTO(terminal->getDisplayedName());
	player->sendSystemMessage(stringID);

	player->sendSystemMessage("@camp:sys_camp_heal"); // While in the camp, medics and entertainers can heal your wounds.

	if (object->isPlayerCreature() && !visitors.contains(object->getObjectID()))
		visitors.add(object->getObjectID());

	if (object->isPlayerCreature())
		object->registerObserver(ObserverEventType::HEALINGPERFORMED, campObserver);
}

void CampSiteActiveAreaImplementation::notifyExit(SceneObject* object) {
	object->dropObserver(ObserverEventType::HEALINGPERFORMED, campObserver);

	if (!object->isPlayerCreature())
		return;

	if (camp == NULL || terminal == NULL)
		return;

	CreatureObject* player = cast<CreatureObject*> (object);

	if (player == NULL)
		return;

	if (camp != NULL)
		camp->removeTemplateSkillMods(player);

	StringIdChatParameter stringID("camp", "prose_camp_exit");
	stringID.setTO(terminal->getDisplayedName());
	player->sendSystemMessage(stringID);

	if(abandoned || object != campOwner)
		return;

	Locker locker(&taskMutex);

	if(!abandoned && abandonTask != NULL && !abandonTask->isScheduled()) {
		try {
			abandonTask->schedule(CampSiteActiveArea::ABANDONTIME);
		} catch (Exception& e) {

		}
	}
}

int CampSiteActiveAreaImplementation::notifyHealEvent(int64 quantity) {
	// Increase XP Pool for heals
	currentXp += (campStructureData->getExperience() / 180);
	return 1;
}

int CampSiteActiveAreaImplementation::notifyCombatEvent() {
	abandonCamp();

	Locker locker(&taskMutex);

	if(abandonTask != NULL)
		if(abandonTask->isScheduled())
			abandonTask->cancel();

	if(campOwner != NULL)
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp"); // Your camp has been abandoned.

	return 1;
}

void CampSiteActiveAreaImplementation::abandonCamp() {
	abandoned = true;

	currentXp = 0;

	Locker locker(&taskMutex);

	if(despawnTask != NULL && despawnTask->isScheduled()) {
		despawnTask->cancel();
		int newTime = (CampSiteActiveArea::DESPAWNTIME / 6);
		int maxTime = CampSiteActiveArea::DESPAWNTIME - ((System::getTime() - timeCreated) * 1000);

		despawnTask->schedule(newTime < maxTime ? newTime : maxTime);
	}

	if(terminal != NULL)
		terminal->setCustomObjectName("Abandoned Camp", true);

	if(campOwner != NULL) {
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);
		campOwner->sendSystemMessage("@camp:sys_abandoned_camp"); // Your camp has been abandoned.
	}
}

bool CampSiteActiveAreaImplementation::despawnCamp() {
	Locker locker(_this.get());

	if(!abandoned && campOwner != NULL && campOwner->getZoneServer() != NULL) {
		/// Get Player Manager
		PlayerManager* playerManager = campOwner->getZoneServer()->getPlayerManager();
		if (playerManager == NULL) {
			error("playerManager is null");
			return false;
		}

		float durationUsed = ((float)(System::getTime() - timeCreated)) / (campStructureData->getDuration() / 4);
		if (durationUsed > 1)
			durationUsed = 1;

		int amount = 0;
		int campXp = campStructureData->getExperience();
		amount = (int)(campXp * durationUsed);

		amount += (int)((visitors.size() -1) * (campXp / 30) * durationUsed);
		amount += (int)(currentXp * durationUsed);

		playerManager->awardExperience(campOwner, "camp", amount, true);
	}

	Locker tlocker(&taskMutex);

	if(despawnTask != NULL ) {
		if(despawnTask->isScheduled())
			despawnTask->cancel();
		despawnTask = NULL;
	}

	if(abandonTask != NULL) {
		if(abandonTask->isScheduled())
			abandonTask->cancel();
		abandonTask = NULL;
	}

	tlocker.release();

	if(campOwner != NULL)
		campOwner->dropObserver(ObserverEventType::STARTCOMBAT, campObserver);

	if (camp != NULL) {
		if(camp->getZone() == NULL)
			return false;

		StructureManager::instance()->destroyStructure(camp);
	}

	destroyObjectFromWorld(true);
	destroyObjectFromDatabase(true);

	return true;
}

void CampSiteActiveAreaImplementation::assumeOwnership(CreatureObject* player) {
	if (camp == NULL || player == NULL)
		return;

	if (player->getSkillMod("camp") < campStructureData->getSkillRequired()) {
		player->sendSystemMessage("@camp:error_too_big"); // You cannot assume ownership of this camp. You lack the skill to maintain a camp of this size.
		return;
	}

	PlayerObject* playerGhost = player->getPlayerObject();

	if (playerGhost == NULL)
		return;

	for (int i = 0; i < playerGhost->getTotalOwnedStructureCount(); ++i) {
		uint64 oid = playerGhost->getOwnedStructure(i);

		ManagedReference<StructureObject*> structure = playerGhost->getZoneServer()->getObject(oid).castTo<StructureObject*>();

		if (structure->isCampStructure()) {
			player->sendSystemMessage("@camp:sys_already_camping"); // But you already have a camp established elsewhere!
			return;
		}
	}

	PlayerObject* ownerGhost = campOwner->getPlayerObject();

	if (ownerGhost != NULL) {
		ownerGhost->removeOwnedStructure(camp);
	}

	setOwner(player);

	abandoned = false;
	currentXp = 0;
	visitors.removeAll();

	Reference<SortedVector<ManagedReference<QuadTreeEntry*> >*> closeObjects = new SortedVector<ManagedReference<QuadTreeEntry*> >();
	zone->getInRangeObjects(camp->getWorldPositionX(), camp->getWorldPositionY(), campStructureData->getRadius(), closeObjects, true);

	for (int i = 0; i < closeObjects->size(); ++i) {
		SceneObject* scno = cast<SceneObject*>(closeObjects->get(i).get());
		if (scno->isPlayerCreature())
			visitors.add(scno->getObjectID());
	}

	playerGhost->addOwnedStructure(camp);

	campOwner->registerObserver(ObserverEventType::STARTCOMBAT, campObserver);

	Locker locker(&taskMutex);

	if(abandonTask != NULL && abandonTask->isScheduled())
		abandonTask->cancel();

	if(despawnTask != NULL && despawnTask->isScheduled())
		despawnTask->cancel();

	timeCreated = System::getTime();
	despawnTask->schedule(CampSiteActiveArea::DESPAWNTIME);

	if(terminal != NULL) {
		String campName = campOwner->getFirstName();
		if(!campOwner->getLastName().isEmpty())
			campName += " " + campOwner->getLastName();
		campName += "'s Camp";
		terminal->setCustomObjectName(campName, true);
	}

	player->sendSystemMessage("@camp:assuming_ownership"); //You assume ownership of the camp.
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/extensions/lt_trackers.hpp"

using boost::filesystem::remove_all;
using boost::tuples::ignore;

void test_main()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49130, 50000), "0.0.0.0", 0);
	ses1.add_extension(create_lt_trackers_plugin);
	ses2.add_extension(create_lt_trackers_plugin);

	add_torrent_params atp;
	atp.info_hash = sha1_hash("12345678901234567890");
	atp.save_path = "./";
	torrent_handle tor1 = ses1.add_torrent(atp);
	atp.tracker_url = "http://test.non-existent.com/announce";
	torrent_handle tor2 = ses2.add_torrent(atp);
	tor2.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), ses1.listen_port()));

	for (int i = 0; i < 130; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (tor1.trackers().size() == 1) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor1.trackers().size() == 1);
}

<commit_msg>fixed test_trackers_extension<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/extensions/lt_trackers.hpp"

using boost::filesystem::remove_all;
using boost::tuples::ignore;

int test_main()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49130, 50000), "0.0.0.0", 0);
	ses1.add_extension(create_lt_trackers_plugin);
	ses2.add_extension(create_lt_trackers_plugin);

	add_torrent_params atp;
	atp.info_hash = sha1_hash("12345678901234567890");
	atp.save_path = "./";
	torrent_handle tor1 = ses1.add_torrent(atp);
	atp.tracker_url = "http://test.non-existent.com/announce";
	torrent_handle tor2 = ses2.add_torrent(atp);
	tor2.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), ses1.listen_port()));

	for (int i = 0; i < 130; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (tor1.trackers().size() == 1) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor1.trackers().size() == 1);
}

<|endoftext|>


<commit_before>//===- Expressions.cpp - Expression Analysis Utilities ----------------------=//
//
// This file defines a package of expression analysis utilties:
//
// ClassifyExpression: Analyze an expression to determine the complexity of the
//   expression, and which other variables it depends on.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Expressions.h"
#include "llvm/Optimizations/ConstantHandling.h"
#include "llvm/ConstantPool.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"

using namespace opt;  // Get all the constant handling stuff
using namespace analysis;

class DefVal {
  const ConstPoolInt * const Val;
  ConstantPool &CP;
  const Type * const Ty;
protected:
  inline DefVal(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : Val(val), CP(cp), Ty(ty) {}
public:
  inline const Type *getType() const { return Ty; }
  inline ConstantPool &getCP() const { return CP; }
  inline const ConstPoolInt *getVal() const { return Val; }
  inline operator const ConstPoolInt * () const { return Val; }
  inline const ConstPoolInt *operator->() const { return Val; }
};

struct DefZero : public DefVal {
  inline DefZero(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : DefVal(val, cp, ty) {}
  inline DefZero(const ConstPoolInt *val)
    : DefVal(val, (ConstantPool&)val->getParent()->getConstantPool(),
	     val->getType()) {}
};

struct DefOne : public DefVal {
  inline DefOne(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : DefVal(val, cp, ty) {}
};

// getIntegralConstant - Wrapper around the ConstPoolInt member of the same
// name.  This method first checks to see if the desired constant is already in
// the constant pool.  If it is, it is quickly recycled, otherwise a new one
// is allocated and added to the constant pool.
//
static ConstPoolInt *getIntegralConstant(ConstantPool &CP, unsigned char V,
					 const Type *Ty) {
  // FIXME: Lookup prexisting constant in table!

  ConstPoolInt *CPI = ConstPoolInt::get(Ty, V);
  CP.insert(CPI);
  return CPI;
}

static ConstPoolInt *getUnsignedConstant(ConstantPool &CP, uint64_t V,
					 const Type *Ty) {
  // FIXME: Lookup prexisting constant in table!

  ConstPoolInt *CPI;
  CPI = Ty->isSigned() ? new ConstPoolSInt(Ty, V) : new ConstPoolUInt(Ty, V);
  CP.insert(CPI);
  return CPI;
}

// Add - Helper function to make later code simpler.  Basically it just adds
// the two constants together, inserts the result into the constant pool, and
// returns it.  Of course life is not simple, and this is no exception.  Factors
// that complicate matters:
//   1. Either argument may be null.  If this is the case, the null argument is
//      treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
//   2. Types get in the way.  We want to do arithmetic operations without
//      regard for the underlying types.  It is assumed that the constants are
//      integral constants.  The new value takes the type of the left argument.
//   3. If DefOne is true, a null return value indicates a value of 1, if DefOne
//      is false, a null return value indicates a value of 0.
//
static const ConstPoolInt *Add(ConstantPool &CP, const ConstPoolInt *Arg1,
			       const ConstPoolInt *Arg2, bool DefOne) {
  assert(Arg1 && Arg2 && "No null arguments should exist now!");
  assert(Arg1->getType() == Arg2->getType() && "Types must be compatible!");

  // Actually perform the computation now!
  ConstPoolVal *Result = *Arg1 + *Arg2;
  assert(Result && Result->getType() == Arg1->getType() &&
	 "Couldn't perform addition!");
  ConstPoolInt *ResultI = (ConstPoolInt*)Result;

  // Check to see if the result is one of the special cases that we want to
  // recognize...
  if (ResultI->equalsInt(DefOne ? 1 : 0)) {
    // Yes it is, simply delete the constant and return null.
    delete ResultI;
    return 0;
  }

  CP.insert(ResultI);
  return ResultI;
}

inline const ConstPoolInt *operator+(const DefZero &L, const DefZero &R) {
  if (L == 0) return R;
  if (R == 0) return L;
  return Add(L.getCP(), L, R, false);
}

inline const ConstPoolInt *operator+(const DefOne &L, const DefOne &R) {
  if (L == 0) {
    if (R == 0)
      return getIntegralConstant(L.getCP(), 2, L.getType());
    else
      return Add(L.getCP(), getIntegralConstant(L.getCP(), 1, L.getType()),
		 R, true);
  } else if (R == 0) {
    return Add(L.getCP(), L,
	       getIntegralConstant(L.getCP(), 1, L.getType()), true);
  }
  return Add(L.getCP(), L, R, true);
}

// Mul - Helper function to make later code simpler.  Basically it just
// multiplies the two constants together, inserts the result into the constant
// pool, and returns it.  Of course life is not simple, and this is no
// exception.  Factors that complicate matters:
//   1. Either argument may be null.  If this is the case, the null argument is
//      treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
//   2. Types get in the way.  We want to do arithmetic operations without
//      regard for the underlying types.  It is assumed that the constants are
//      integral constants.
//   3. If DefOne is true, a null return value indicates a value of 1, if DefOne
//      is false, a null return value indicates a value of 0.
//
inline const ConstPoolInt *Mul(ConstantPool &CP, const ConstPoolInt *Arg1,
			       const ConstPoolInt *Arg2, bool DefOne = false) {
  assert(Arg1 && Arg2 && "No null arguments should exist now!");
  assert(Arg1->getType() == Arg2->getType() && "Types must be compatible!");

  // Actually perform the computation now!
  ConstPoolVal *Result = *Arg1 * *Arg2;
  assert(Result && Result->getType() == Arg1->getType() &&
	 "Couldn't perform mult!");
  ConstPoolInt *ResultI = (ConstPoolInt*)Result;

  // Check to see if the result is one of the special cases that we want to
  // recognize...
  if (ResultI->equalsInt(DefOne ? 1 : 0)) {
    // Yes it is, simply delete the constant and return null.
    delete ResultI;
    return 0;
  }

  CP.insert(ResultI);
  return ResultI;
}

inline const ConstPoolInt *operator*(const DefZero &L, const DefZero &R) {
  if (L == 0 || R == 0) return 0;
  return Mul(L.getCP(), L, R, false);
}
inline const ConstPoolInt *operator*(const DefOne &L, const DefZero &R) {
  if (R == 0) return getIntegralConstant(L.getCP(), 0, L.getType());
  if (L == 0) return R->equalsInt(1) ? 0 : R.getVal();
  return Mul(L.getCP(), L, R, false);
}
inline const ConstPoolInt *operator*(const DefZero &L, const DefOne &R) {
  return R*L;
}

// ClassifyExpression: Analyze an expression to determine the complexity of the
// expression, and which other values it depends on.
//
// Note that this analysis cannot get into infinite loops because it treats PHI
// nodes as being an unknown linear expression.
//
ExprType analysis::ClassifyExpression(Value *Expr) {
  assert(Expr != 0 && "Can't classify a null expression!");
  switch (Expr->getValueType()) {
  case Value::InstructionVal: break;    // Instruction... hmmm... investigate.
  case Value::TypeVal:   case Value::BasicBlockVal:
  case Value::MethodVal: case Value::ModuleVal:
    assert(0 && "Unexpected expression type to classify!");
  case Value::MethodArgumentVal:        // Method arg: nothing known, return var
    return Expr;
  case Value::ConstantVal:              // Constant value, just return constant
    ConstPoolVal *CPV = Expr->castConstantAsserting();
    if (CPV->getType()->isIntegral()) { // It's an integral constant!
      ConstPoolInt *CPI = (ConstPoolInt*)Expr;
      return ExprType(CPI->equalsInt(0) ? 0 : (ConstPoolInt*)Expr);
    }
    return Expr;
  }

  Instruction *I = Expr->castInstructionAsserting();
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();
  const Type *Ty = I->getType();

  switch (I->getOpcode()) {       // Handle each instruction type seperately
  case Instruction::Add: {
    ExprType Left (ClassifyExpression(I->getOperand(0)));
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Left.ExprTy > Right.ExprTy)
      swap(Left, Right);   // Make left be simpler than right

    switch (Left.ExprTy) {
    case ExprType::Constant:
      return ExprType(Right.Scale, Right.Var,
		      DefZero(Right.Offset,CP,Ty) + DefZero(Left.Offset, CP,Ty));
    case ExprType::Linear:        // RHS side must be linear or scaled
    case ExprType::ScaledLinear:  // RHS must be scaled
      if (Left.Var != Right.Var)        // Are they the same variables?
	return ExprType(I);       //   if not, we don't know anything!

      return ExprType(DefOne(Left.Scale  ,CP,Ty) + DefOne(Right.Scale  , CP,Ty),
		      Left.Var,
	              DefZero(Left.Offset,CP,Ty) + DefZero(Right.Offset, CP,Ty));
    }
  }  // end case Instruction::Add

  case Instruction::Shl: {
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Right.ExprTy != ExprType::Constant) break;
    ExprType Left(ClassifyExpression(I->getOperand(0)));
    if (Right.Offset == 0) return Left;   // shl x, 0 = x
    assert(Right.Offset->getType() == Type::UByteTy &&
	   "Shift amount must always be a unsigned byte!");
    uint64_t ShiftAmount = ((ConstPoolUInt*)Right.Offset)->getValue();
    ConstPoolInt *Multiplier = getUnsignedConstant(CP, 1ULL << ShiftAmount, Ty);

    return ExprType(DefOne(Left.Scale, CP, Ty) * Multiplier,
		    Left.Var,
		    DefZero(Left.Offset, CP, Ty) * Multiplier);
  }  // end case Instruction::Shl

  case Instruction::Mul: {
    ExprType Left (ClassifyExpression(I->getOperand(0)));
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Left.ExprTy > Right.ExprTy)
      swap(Left, Right);   // Make left be simpler than right

    if (Left.ExprTy != ExprType::Constant)  // RHS must be > constant
      return I;         // Quadratic eqn! :(

    const ConstPoolInt *Offs = Left.Offset;
    if (Offs == 0) return ExprType();
    return ExprType(DefOne(Right.Scale, CP, Ty) * Offs,
		    Right.Var,
		    DefZero(Right.Offset, CP, Ty) * Offs);
  } // end case Instruction::Mul

  case Instruction::Cast: {
    ExprType Src(ClassifyExpression(I->getOperand(0)));
    if (Src.ExprTy != ExprType::Constant)
      return I;
    const ConstPoolInt *Offs = Src.Offset;
    if (Offs == 0) return ExprType();

    if (I->getType()->isPointerType())
      return Offs;  // Pointer types do not lose precision

    assert(I->getType()->isIntegral() && "Can only handle integral types!");

    const ConstPoolVal *CPV = ConstRules::get(*Offs)->castTo(Offs, I->getType());
    if (!CPV) return I;
    assert(CPV->getType()->isIntegral() && "Must have an integral type!");
    return (ConstPoolInt*)CPV;
  } // end case Instruction::Cast
    // TODO: Handle SUB (at least!)

  }  // end switch

  // Otherwise, I don't know anything about this value!
  return I;
}
<commit_msg>Fix a bug when compiling 'shl ubyte * %var, ubyte 2'<commit_after>//===- Expressions.cpp - Expression Analysis Utilities ----------------------=//
//
// This file defines a package of expression analysis utilties:
//
// ClassifyExpression: Analyze an expression to determine the complexity of the
//   expression, and which other variables it depends on.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Expressions.h"
#include "llvm/Optimizations/ConstantHandling.h"
#include "llvm/ConstantPool.h"
#include "llvm/Method.h"
#include "llvm/BasicBlock.h"

using namespace opt;  // Get all the constant handling stuff
using namespace analysis;

class DefVal {
  const ConstPoolInt * const Val;
  ConstantPool &CP;
  const Type * const Ty;
protected:
  inline DefVal(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : Val(val), CP(cp), Ty(ty) {}
public:
  inline const Type *getType() const { return Ty; }
  inline ConstantPool &getCP() const { return CP; }
  inline const ConstPoolInt *getVal() const { return Val; }
  inline operator const ConstPoolInt * () const { return Val; }
  inline const ConstPoolInt *operator->() const { return Val; }
};

struct DefZero : public DefVal {
  inline DefZero(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : DefVal(val, cp, ty) {}
  inline DefZero(const ConstPoolInt *val)
    : DefVal(val, (ConstantPool&)val->getParent()->getConstantPool(),
	     val->getType()) {}
};

struct DefOne : public DefVal {
  inline DefOne(const ConstPoolInt *val, ConstantPool &cp, const Type *ty)
    : DefVal(val, cp, ty) {}
};

// getIntegralConstant - Wrapper around the ConstPoolInt member of the same
// name.  This method first checks to see if the desired constant is already in
// the constant pool.  If it is, it is quickly recycled, otherwise a new one
// is allocated and added to the constant pool.
//
static ConstPoolInt *getIntegralConstant(ConstantPool &CP, unsigned char V,
					 const Type *Ty) {
  // FIXME: Lookup prexisting constant in table!

  ConstPoolInt *CPI = ConstPoolInt::get(Ty, V);
  CP.insert(CPI);
  return CPI;
}

static ConstPoolInt *getUnsignedConstant(ConstantPool &CP, uint64_t V,
					 const Type *Ty) {
  // FIXME: Lookup prexisting constant in table!
  if (Ty->isPointerType()) Ty = Type::ULongTy;

  ConstPoolInt *CPI;
  CPI = Ty->isSigned() ? new ConstPoolSInt(Ty, V) : new ConstPoolUInt(Ty, V);
  CP.insert(CPI);
  return CPI;
}

// Add - Helper function to make later code simpler.  Basically it just adds
// the two constants together, inserts the result into the constant pool, and
// returns it.  Of course life is not simple, and this is no exception.  Factors
// that complicate matters:
//   1. Either argument may be null.  If this is the case, the null argument is
//      treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
//   2. Types get in the way.  We want to do arithmetic operations without
//      regard for the underlying types.  It is assumed that the constants are
//      integral constants.  The new value takes the type of the left argument.
//   3. If DefOne is true, a null return value indicates a value of 1, if DefOne
//      is false, a null return value indicates a value of 0.
//
static const ConstPoolInt *Add(ConstantPool &CP, const ConstPoolInt *Arg1,
			       const ConstPoolInt *Arg2, bool DefOne) {
  assert(Arg1 && Arg2 && "No null arguments should exist now!");
  assert(Arg1->getType() == Arg2->getType() && "Types must be compatible!");

  // Actually perform the computation now!
  ConstPoolVal *Result = *Arg1 + *Arg2;
  assert(Result && Result->getType() == Arg1->getType() &&
	 "Couldn't perform addition!");
  ConstPoolInt *ResultI = (ConstPoolInt*)Result;

  // Check to see if the result is one of the special cases that we want to
  // recognize...
  if (ResultI->equalsInt(DefOne ? 1 : 0)) {
    // Yes it is, simply delete the constant and return null.
    delete ResultI;
    return 0;
  }

  CP.insert(ResultI);
  return ResultI;
}

inline const ConstPoolInt *operator+(const DefZero &L, const DefZero &R) {
  if (L == 0) return R;
  if (R == 0) return L;
  return Add(L.getCP(), L, R, false);
}

inline const ConstPoolInt *operator+(const DefOne &L, const DefOne &R) {
  if (L == 0) {
    if (R == 0)
      return getIntegralConstant(L.getCP(), 2, L.getType());
    else
      return Add(L.getCP(), getIntegralConstant(L.getCP(), 1, L.getType()),
		 R, true);
  } else if (R == 0) {
    return Add(L.getCP(), L,
	       getIntegralConstant(L.getCP(), 1, L.getType()), true);
  }
  return Add(L.getCP(), L, R, true);
}

// Mul - Helper function to make later code simpler.  Basically it just
// multiplies the two constants together, inserts the result into the constant
// pool, and returns it.  Of course life is not simple, and this is no
// exception.  Factors that complicate matters:
//   1. Either argument may be null.  If this is the case, the null argument is
//      treated as either 0 (if DefOne = false) or 1 (if DefOne = true)
//   2. Types get in the way.  We want to do arithmetic operations without
//      regard for the underlying types.  It is assumed that the constants are
//      integral constants.
//   3. If DefOne is true, a null return value indicates a value of 1, if DefOne
//      is false, a null return value indicates a value of 0.
//
inline const ConstPoolInt *Mul(ConstantPool &CP, const ConstPoolInt *Arg1,
			       const ConstPoolInt *Arg2, bool DefOne = false) {
  assert(Arg1 && Arg2 && "No null arguments should exist now!");
  assert(Arg1->getType() == Arg2->getType() && "Types must be compatible!");

  // Actually perform the computation now!
  ConstPoolVal *Result = *Arg1 * *Arg2;
  assert(Result && Result->getType() == Arg1->getType() &&
	 "Couldn't perform mult!");
  ConstPoolInt *ResultI = (ConstPoolInt*)Result;

  // Check to see if the result is one of the special cases that we want to
  // recognize...
  if (ResultI->equalsInt(DefOne ? 1 : 0)) {
    // Yes it is, simply delete the constant and return null.
    delete ResultI;
    return 0;
  }

  CP.insert(ResultI);
  return ResultI;
}

inline const ConstPoolInt *operator*(const DefZero &L, const DefZero &R) {
  if (L == 0 || R == 0) return 0;
  return Mul(L.getCP(), L, R, false);
}
inline const ConstPoolInt *operator*(const DefOne &L, const DefZero &R) {
  if (R == 0) return getIntegralConstant(L.getCP(), 0, L.getType());
  if (L == 0) return R->equalsInt(1) ? 0 : R.getVal();
  return Mul(L.getCP(), L, R, false);
}
inline const ConstPoolInt *operator*(const DefZero &L, const DefOne &R) {
  return R*L;
}

// ClassifyExpression: Analyze an expression to determine the complexity of the
// expression, and which other values it depends on.
//
// Note that this analysis cannot get into infinite loops because it treats PHI
// nodes as being an unknown linear expression.
//
ExprType analysis::ClassifyExpression(Value *Expr) {
  assert(Expr != 0 && "Can't classify a null expression!");
  switch (Expr->getValueType()) {
  case Value::InstructionVal: break;    // Instruction... hmmm... investigate.
  case Value::TypeVal:   case Value::BasicBlockVal:
  case Value::MethodVal: case Value::ModuleVal:
    assert(0 && "Unexpected expression type to classify!");
  case Value::MethodArgumentVal:        // Method arg: nothing known, return var
    return Expr;
  case Value::ConstantVal:              // Constant value, just return constant
    ConstPoolVal *CPV = Expr->castConstantAsserting();
    if (CPV->getType()->isIntegral()) { // It's an integral constant!
      ConstPoolInt *CPI = (ConstPoolInt*)Expr;
      return ExprType(CPI->equalsInt(0) ? 0 : (ConstPoolInt*)Expr);
    }
    return Expr;
  }

  Instruction *I = Expr->castInstructionAsserting();
  ConstantPool &CP = I->getParent()->getParent()->getConstantPool();
  const Type *Ty = I->getType();

  switch (I->getOpcode()) {       // Handle each instruction type seperately
  case Instruction::Add: {
    ExprType Left (ClassifyExpression(I->getOperand(0)));
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Left.ExprTy > Right.ExprTy)
      swap(Left, Right);   // Make left be simpler than right

    switch (Left.ExprTy) {
    case ExprType::Constant:
      return ExprType(Right.Scale, Right.Var,
		      DefZero(Right.Offset,CP,Ty) + DefZero(Left.Offset, CP,Ty));
    case ExprType::Linear:        // RHS side must be linear or scaled
    case ExprType::ScaledLinear:  // RHS must be scaled
      if (Left.Var != Right.Var)        // Are they the same variables?
	return ExprType(I);       //   if not, we don't know anything!

      return ExprType(DefOne(Left.Scale  ,CP,Ty) + DefOne(Right.Scale  , CP,Ty),
		      Left.Var,
	              DefZero(Left.Offset,CP,Ty) + DefZero(Right.Offset, CP,Ty));
    }
  }  // end case Instruction::Add

  case Instruction::Shl: {
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Right.ExprTy != ExprType::Constant) break;
    ExprType Left(ClassifyExpression(I->getOperand(0)));
    if (Right.Offset == 0) return Left;   // shl x, 0 = x
    assert(Right.Offset->getType() == Type::UByteTy &&
	   "Shift amount must always be a unsigned byte!");
    uint64_t ShiftAmount = ((ConstPoolUInt*)Right.Offset)->getValue();
    ConstPoolInt *Multiplier = getUnsignedConstant(CP, 1ULL << ShiftAmount, Ty);

    return ExprType(DefOne(Left.Scale, CP, Ty) * Multiplier,
		    Left.Var,
		    DefZero(Left.Offset, CP, Ty) * Multiplier);
  }  // end case Instruction::Shl

  case Instruction::Mul: {
    ExprType Left (ClassifyExpression(I->getOperand(0)));
    ExprType Right(ClassifyExpression(I->getOperand(1)));
    if (Left.ExprTy > Right.ExprTy)
      swap(Left, Right);   // Make left be simpler than right

    if (Left.ExprTy != ExprType::Constant)  // RHS must be > constant
      return I;         // Quadratic eqn! :(

    const ConstPoolInt *Offs = Left.Offset;
    if (Offs == 0) return ExprType();
    return ExprType(DefOne(Right.Scale, CP, Ty) * Offs,
		    Right.Var,
		    DefZero(Right.Offset, CP, Ty) * Offs);
  } // end case Instruction::Mul

  case Instruction::Cast: {
    ExprType Src(ClassifyExpression(I->getOperand(0)));
    if (Src.ExprTy != ExprType::Constant)
      return I;
    const ConstPoolInt *Offs = Src.Offset;
    if (Offs == 0) return ExprType();

    if (I->getType()->isPointerType())
      return Offs;  // Pointer types do not lose precision

    assert(I->getType()->isIntegral() && "Can only handle integral types!");

    const ConstPoolVal *CPV = ConstRules::get(*Offs)->castTo(Offs, I->getType());
    if (!CPV) return I;
    assert(CPV->getType()->isIntegral() && "Must have an integral type!");
    return (ConstPoolInt*)CPV;
  } // end case Instruction::Cast
    // TODO: Handle SUB, SHR?

  }  // end switch

  // Otherwise, I don't know anything about this value!
  return I;
}
<|endoftext|>


<commit_before>/*
 * fetcher.cpp
 *
 *  Created on: Nov 21, 2012
 *      Author: partio
 */

#include "fetcher.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/operations.hpp>
#include "util.h"

#define HIMAN_AUXILIARY_INCLUDE

#include "grib.h"
#include "neons.h"
#include "param.h"
#include "cache.h"
#include "querydata.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace himan::plugin;
using namespace std;

const unsigned int sleepSeconds = 10;

fetcher::fetcher()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("fetcher"));
}

shared_ptr<himan::info> fetcher::Fetch(shared_ptr<const configuration> config,
                                       const forecast_time& requestedTime,
                                       const level& requestedLevel,
                                       const param& requestedParam)
{

    const search_options opts { requestedTime, requestedParam, requestedLevel, config } ;

    vector<shared_ptr<info>> theInfos;

    for (unsigned int waitedSeconds = 0; waitedSeconds < config->FileWaitTimeout() * 60; waitedSeconds += sleepSeconds)
    {
    	// 1. Fetch data from cache

    	// theInfos = FromCache()

    	/*
    	 *  2. Fetch data from auxiliary files specified at command line
    	 *
    	 *  Even if file_wait_timeout is specified, auxiliary files is searched
    	 *  only once.
    	 */

    	if (config->AuxiliaryFiles().size() && waitedSeconds == 0)
    	{
    		theInfos = FromFile(config->AuxiliaryFiles(), opts, true);

    		if (theInfos.size())
    		{
    			itsLogger->Debug("Data found from auxiliary file(s)");
    			break;
    		}
    		else
    		{
    			itsLogger->Warning("Data not found from auxiliary file(s)");
    		}
    	}

		// 3. Fetch data from Neons

		vector<string> files;

		if (config->ReadDataFromDatabase())
		{
			shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

			files = n->Files(opts);

			if (!files.empty())
			{
				theInfos = FromFile(files, opts, true);

				break;
			}
	    	else if (config->ReadDataFromDatabase())
	    	{
	    		itsLogger->Debug("Could not find file(s) from Neons matching requested parameters");
	    	}
		}

		if (config->FileWaitTimeout() > 0)
		{
			itsLogger->Debug("Sleeping for " + boost::lexical_cast<string> (sleepSeconds) + " seconds (cumulative: " + boost::lexical_cast<string> (waitedSeconds) + ")");

			if (!config->ReadDataFromDatabase())
			{
				itsLogger->Warning("file_wait_timeout specified but file read from Neons is disabled");
			}

			sleep(sleepSeconds);
		}
    }

    /*
     *  Safeguard; later in the code we do not check whether the data requested
     *  was actually what was requested.
     */

	if (theInfos.size() == 0)
	{
		string optsStr = "producer: " + boost::lexical_cast<string> (config->SourceProducer());
		optsStr += " origintime: " + requestedTime.OriginDateTime()->String() + ", step: " + boost::lexical_cast<string> (requestedTime.Step());
		optsStr += " param: " + requestedParam.Name();
		optsStr += " level: " + string(himan::HPLevelTypeToString.at(requestedLevel.Type())) + " " + boost::lexical_cast<string> (requestedLevel.Value());

		itsLogger->Warning("No valid data found with given search options " + optsStr);

		throw kFileDataNotFound;
	}

    // assert(theConfiguration->SourceProducer() == theInfos[0]->Producer());

    assert((theInfos[0]->Level()) == requestedLevel);

    assert((theInfos[0]->Time()) == requestedTime);

    assert((theInfos[0]->Param()) == requestedParam);

    return theInfos[0];

}

/*
 * FromFile()
 *
 * Get data and metadata from a file. Returns a vector of infos, mainly because one grib file can
 * contain many grib messages. If read file is querydata, the vector size is always one (or zero if the
 * read fails).
 */

vector<shared_ptr<himan::info>> fetcher::FromFile(const vector<string>& files, const search_options& options, bool readContents)
{

    vector<shared_ptr<himan::info>> allInfos ;

    for (size_t i = 0; i < files.size(); i++)
    {
        string inputFile = files[i];

        if (!boost::filesystem::exists(inputFile))
        {
            itsLogger->Error("Input file '" + inputFile + "' does not exist");
            continue;
        }

        vector<shared_ptr<himan::info>> curInfos;

        switch (util::FileType(inputFile))
        {

        case kGRIB:
        case kGRIB1:
        case kGRIB2:
        {

            curInfos = FromGrib(inputFile, options, readContents);
            break;

        }

        case kQueryData:
        {

            curInfos = FromQueryData(inputFile, options, readContents);
            break;
        }

        case kNetCDF:
            cout << "File is NetCDF" << endl;
            break;

        default:
            // Unknown file type, cannot proceed
            throw runtime_error("Input file is neither GRID, NetCDF nor QueryData");
            break;
        }

        allInfos.insert(allInfos.end(), curInfos.begin(), curInfos.end());

        if (curInfos.size())
        {
            break; // We found what we were looking for
        }

    }

    return allInfos;
}

vector<shared_ptr<himan::info> > fetcher::FromGrib(const string& inputFile, const search_options& options, bool readContents)
{

    shared_ptr<grib> g = dynamic_pointer_cast<grib> (plugin_factory::Instance()->Plugin("grib"));

    vector<shared_ptr<info>> infos = g->FromFile(inputFile, options, readContents);

    return infos;
}

vector<shared_ptr<himan::info>> fetcher::FromQueryData(const string& inputFile, const search_options& options, bool readContents)
{

    shared_ptr<querydata> q = dynamic_pointer_cast<querydata> (plugin_factory::Instance()->Plugin("querydata"));

    shared_ptr<info> i = q->FromFile(inputFile, options, readContents);

    vector<shared_ptr<info>> theInfos;

    theInfos.push_back(i);

    return theInfos;
}
<commit_msg>change for to do/while<commit_after>/*
 * fetcher.cpp
 *
 *  Created on: Nov 21, 2012
 *      Author: partio
 */

#include "fetcher.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem/operations.hpp>
#include "util.h"

#define HIMAN_AUXILIARY_INCLUDE

#include "grib.h"
#include "neons.h"
#include "param.h"
#include "cache.h"
#include "querydata.h"

#undef HIMAN_AUXILIARY_INCLUDE

using namespace himan::plugin;
using namespace std;

const unsigned int sleepSeconds = 10;

fetcher::fetcher()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("fetcher"));
}

shared_ptr<himan::info> fetcher::Fetch(shared_ptr<const configuration> config,
                                       const forecast_time& requestedTime,
                                       const level& requestedLevel,
                                       const param& requestedParam)
{

    const search_options opts { requestedTime, requestedParam, requestedLevel, config } ;

    vector<shared_ptr<info>> theInfos;
    unsigned int waitedSeconds = 0;

    do
    {
    	// 1. Fetch data from cache

    	// theInfos = FromCache()

    	/*
    	 *  2. Fetch data from auxiliary files specified at command line
    	 *
    	 *  Even if file_wait_timeout is specified, auxiliary files is searched
    	 *  only once.
    	 */

    	if (config->AuxiliaryFiles().size() && waitedSeconds == 0)
    	{
    		theInfos = FromFile(config->AuxiliaryFiles(), opts, true);

    		if (theInfos.size())
    		{
    			itsLogger->Debug("Data found from auxiliary file(s)");
    			break;
    		}
    		else
    		{
    			itsLogger->Warning("Data not found from auxiliary file(s)");
    		}
    	}

		// 3. Fetch data from Neons

		vector<string> files;

		if (config->ReadDataFromDatabase())
		{
			shared_ptr<neons> n = dynamic_pointer_cast<neons> (plugin_factory::Instance()->Plugin("neons"));

			files = n->Files(opts);

			if (!files.empty())
			{
				theInfos = FromFile(files, opts, true);

				break;
			}
	    	else if (config->ReadDataFromDatabase())
	    	{
	    		itsLogger->Debug("Could not find file(s) from Neons matching requested parameters");
	    	}
		}

		if (config->FileWaitTimeout() > 0)
		{
			itsLogger->Debug("Sleeping for " + boost::lexical_cast<string> (sleepSeconds) + " seconds (cumulative: " + boost::lexical_cast<string> (waitedSeconds) + ")");

			if (!config->ReadDataFromDatabase())
			{
				itsLogger->Warning("file_wait_timeout specified but file read from Neons is disabled");
			}

			sleep(sleepSeconds);
		}

		waitedSeconds += sleepSeconds;
    }
    while (waitedSeconds < config->FileWaitTimeout() * 60);

    /*
     *  Safeguard; later in the code we do not check whether the data requested
     *  was actually what was requested.
     */

	if (theInfos.size() == 0)
	{
		string optsStr = "producer: " + boost::lexical_cast<string> (config->SourceProducer());
		optsStr += " origintime: " + requestedTime.OriginDateTime()->String() + ", step: " + boost::lexical_cast<string> (requestedTime.Step());
		optsStr += " param: " + requestedParam.Name();
		optsStr += " level: " + string(himan::HPLevelTypeToString.at(requestedLevel.Type())) + " " + boost::lexical_cast<string> (requestedLevel.Value());

		itsLogger->Warning("No valid data found with given search options " + optsStr);

		throw kFileDataNotFound;
	}

    // assert(theConfiguration->SourceProducer() == theInfos[0]->Producer());

    assert((theInfos[0]->Level()) == requestedLevel);

    assert((theInfos[0]->Time()) == requestedTime);

    assert((theInfos[0]->Param()) == requestedParam);

    return theInfos[0];

}

/*
 * FromFile()
 *
 * Get data and metadata from a file. Returns a vector of infos, mainly because one grib file can
 * contain many grib messages. If read file is querydata, the vector size is always one (or zero if the
 * read fails).
 */

vector<shared_ptr<himan::info>> fetcher::FromFile(const vector<string>& files, const search_options& options, bool readContents)
{

    vector<shared_ptr<himan::info>> allInfos ;

    for (size_t i = 0; i < files.size(); i++)
    {
        string inputFile = files[i];

        if (!boost::filesystem::exists(inputFile))
        {
            itsLogger->Error("Input file '" + inputFile + "' does not exist");
            continue;
        }

        vector<shared_ptr<himan::info>> curInfos;

        switch (util::FileType(inputFile))
        {

        case kGRIB:
        case kGRIB1:
        case kGRIB2:
        {

            curInfos = FromGrib(inputFile, options, readContents);
            break;

        }

        case kQueryData:
        {

            curInfos = FromQueryData(inputFile, options, readContents);
            break;
        }

        case kNetCDF:
            cout << "File is NetCDF" << endl;
            break;

        default:
            // Unknown file type, cannot proceed
            throw runtime_error("Input file is neither GRID, NetCDF nor QueryData");
            break;
        }

        allInfos.insert(allInfos.end(), curInfos.begin(), curInfos.end());

        if (curInfos.size())
        {
            break; // We found what we were looking for
        }

    }

    return allInfos;
}

vector<shared_ptr<himan::info> > fetcher::FromGrib(const string& inputFile, const search_options& options, bool readContents)
{

    shared_ptr<grib> g = dynamic_pointer_cast<grib> (plugin_factory::Instance()->Plugin("grib"));

    vector<shared_ptr<info>> infos = g->FromFile(inputFile, options, readContents);

    return infos;
}

vector<shared_ptr<himan::info>> fetcher::FromQueryData(const string& inputFile, const search_options& options, bool readContents)
{

    shared_ptr<querydata> q = dynamic_pointer_cast<querydata> (plugin_factory::Instance()->Plugin("querydata"));

    shared_ptr<info> i = q->FromFile(inputFile, options, readContents);

    vector<shared_ptr<info>> theInfos;

    theInfos.push_back(i);

    return theInfos;
}
<|endoftext|>