<commit_before>#include "dsa_common.h"

#include "path.h"

#include <boost/algorithm/string/join.hpp>

static bool invalid_name(const std::string &name, bool is_meta) {
  if (name.empty()) return true;
  if (!is_meta && (name[0] == '@' || name[0] == '$')) {
    // attribute and metadata name can not show up in parent node
    return true;
  }
  if (name[0] == '.' && (name.size() == 1 || name[1] == '.')) {
    // name can not be '.' or start with '..'
    return true;
  }
  int check_escape = 0;
  for (const char &c : name) {  // invalid characters
    if (check_escape > 0) {
      // % must be followed by 2 upper case hex bytes
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
          (c >= 'a' && c <= 'f')) {
        check_escape--;
        continue;
      }
      return true;  // invalid hex
    }

    // invalid characters
    if (c < ' ' || (c >= ':' && c <= '?') || c == '\\' || c == '\'' ||
        c == '\"' || c == '/' || c == '*' || c == '|') {
      return true;
    }
    if (c == '%') {
      check_escape = 2;
    }
  }
  return check_escape != 0;
}

namespace dsa {

PathData::PathData(const std::string &path) : str(path) {
  if (path.empty()) {
    is_root = true;
    return;
  }
  auto current = path.begin();
  auto end = path.end();

  while (true) {
    auto next = std::find(current, end, '/');
    std::string name = std::string(current, next);
    if (invalid_name(name, false)) {
      invalid = true;
      return;
    }
    names.emplace_back(std::move(name));
    if (next == end) {
      // valid node
      return;
    }
    current = next + 1;
    if (current == end) {
      // end with /
      invalid = true;
      return;
    }
  }
}

PathData::PathData(std::vector<std::string> &&strs) {
  names = std::move(strs);
  if (names.empty()) {
    is_root = true;
    return;
  }
  str = boost::algorithm::join(names, "/");
}

Path::Path(const std::string &path) : _data(make_ref_<PathData>(path)) {}
Path::Path(const ref_<const PathData> &data, size_t idx)
    : _data(data), _current(idx) {}

const std::string &Path::remain_str() const {
  std::string result = current_name();
  size_t size = _data->names.size();
  for (size_t i = _current + 1; i < size; ++i) {
    result.insert(result.size(), "/");
    result.insert(result.size(), _data->names[i]);
  }
  return std::move(result);
}

const Path Path::get_child_path(const std::string &name) {
  if (!invalid_name(name, false)) {
    std::vector<std::string> new_names = _data->names;
    new_names.push_back(name);
    return Path(ref_<PathData>(new PathData(std::move(new_names))), 0);
  } else {
    return Path();
  }
}
const Path Path::get_parent_path() {
  if (!is_invalid() && !is_root()) {
    std::vector<std::string> new_names = _data->names;
    new_names.pop_back();
    return Path(ref_<PathData>(new PathData(std::move(new_names))), 0);
  } else {
    return Path();
  }
}
const Path Path::copy() {
  return Path(ref_<PathData>(new PathData(*_data)), _current);
}
}
<commit_msg>not allow .. in path name, but allows name to start with ..<commit_after>#include "dsa_common.h"

#include "path.h"

#include <boost/algorithm/string/join.hpp>

static bool invalid_name(const std::string &name, bool is_meta) {
  if (name.empty()) return true;
  if (!is_meta && (name[0] == '@' || name[0] == '$')) {
    // attribute and metadata name can not show up in parent node
    return true;
  }
  if (name == "." || name == "..") {
    return true;
  }

  int check_escape = 0;
  for (const char &c : name) {  // invalid characters
    if (check_escape > 0) {
      // % must be followed by 2 upper case hex bytes
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
          (c >= 'a' && c <= 'f')) {
        check_escape--;
        continue;
      }
      return true;  // invalid hex
    }

    // invalid characters
    if (c < ' ' || (c >= ':' && c <= '?') || c == '\\' || c == '\'' ||
        c == '\"' || c == '/' || c == '*' || c == '|') {
      return true;
    }
    if (c == '%') {
      check_escape = 2;
    }
  }
  return check_escape != 0;
}

namespace dsa {

PathData::PathData(const std::string &path) : str(path) {
  if (path.empty()) {
    is_root = true;
    return;
  }
  auto current = path.begin();
  auto end = path.end();

  while (true) {
    auto next = std::find(current, end, '/');
    std::string name = std::string(current, next);
    if (invalid_name(name, false)) {
      invalid = true;
      return;
    }
    names.emplace_back(std::move(name));
    if (next == end) {
      // valid node
      return;
    }
    current = next + 1;
    if (current == end) {
      // end with /
      invalid = true;
      return;
    }
  }
}

PathData::PathData(std::vector<std::string> &&strs) {
  names = std::move(strs);
  if (names.empty()) {
    is_root = true;
    return;
  }
  str = boost::algorithm::join(names, "/");
}

Path::Path(const std::string &path) : _data(make_ref_<PathData>(path)) {}
Path::Path(const ref_<const PathData> &data, size_t idx)
    : _data(data), _current(idx) {}

const std::string &Path::remain_str() const {
  std::string result = current_name();
  size_t size = _data->names.size();
  for (size_t i = _current + 1; i < size; ++i) {
    result.insert(result.size(), "/");
    result.insert(result.size(), _data->names[i]);
  }
  return std::move(result);
}

const Path Path::get_child_path(const std::string &name) {
  if (!invalid_name(name, false)) {
    std::vector<std::string> new_names = _data->names;
    new_names.push_back(name);
    return Path(ref_<PathData>(new PathData(std::move(new_names))), 0);
  } else {
    return Path();
  }
}
const Path Path::get_parent_path() {
  if (!is_invalid() && !is_root()) {
    std::vector<std::string> new_names = _data->names;
    new_names.pop_back();
    return Path(ref_<PathData>(new PathData(std::move(new_names))), 0);
  } else {
    return Path();
  }
}
const Path Path::copy() {
  return Path(ref_<PathData>(new PathData(*_data)), _current);
}
}
<|endoftext|>


<commit_before>#include <sigma/window.hpp>

#include <SDL2/SDL.h>

#include <stdexcept>
#include <string>
#include <unordered_map>

namespace sigma {
namespace detail {
    static std::unordered_map<Uint32, window*> created_windows;

    void init_sdl2_if_not_already()
    {
        if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
            if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
                throw std::runtime_error(SDL_GetError());
            }
        }
    }
}

window::window(glm::ivec2 size)
    : size_(size)
    , good_(false)
{
    detail::init_sdl2_if_not_already();

    //SDL_GL_SetAttribute(SDL_GL_RED_SIZE, context_attributes_.red);
    //SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, context_attributes_.green);
    //SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, context_attributes_.blue);
    //SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, context_attributes_.alpha);
    //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, context_attributes_.depth);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
    //SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, context_attributes_.stencil);

    //if(context_attributes_.samples > 0) {
    //    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
    //    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, context_attributes_.samples);
    //}

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);

    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, context_attributes_.major);
    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, context_attributes_.minor);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
    // TODO disable this in production.
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);

    //if(context_attributes_.core_profile)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

    window_ = SDL_CreateWindow(title_.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, size_.x, size_.y, SDL_WINDOW_OPENGL); //| SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS
    if (!window_)
        throw std::runtime_error(SDL_GetError());

    gl_context_ = SDL_GL_CreateContext(window_);
    if (!gl_context_)
        throw std::runtime_error(SDL_GetError());

    SDL_GL_MakeCurrent(window_, gl_context_);

    SDL_GL_SetSwapInterval(0); //context_attributes_.vsync

    good_ = true;
    detail::created_windows[SDL_GetWindowID(window_)] = this;
}

window::~window()
{
    close();
}

glm::ivec2 window::size()
{
    return size_;
}

bool window::good()
{
    /*SDL_Event event;
    while (SDL_PollEvent(&event) != 0) {
        switch (event.type) {
        case SDL_WINDOWEVENT: {
            auto event_window = detail::created_windows[event.window.windowID];
            switch (event.window.event) {
            case SDL_WINDOWEVENT_CLOSE:
                event_window->good_ = false;
                event_window->close();
                break;
            }
            break;
        }
        }
    }*/

    return good_;
}

void window::close()
{
    if (window_) {
        if (gl_context_) {
            SDL_GL_DeleteContext(gl_context_);
            gl_context_ = nullptr;
        }
        SDL_DestroyWindow(window_);
        window_ = nullptr;
        good_ = false;
    }
}
}
<commit_msg>Don't delete the window on close.<commit_after>#include <sigma/window.hpp>

#include <SDL2/SDL.h>

#include <stdexcept>
#include <string>
#include <unordered_map>

namespace sigma {
namespace detail {
    static std::unordered_map<Uint32, window*> created_windows;

    void init_sdl2_if_not_already()
    {
        if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
            if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
                throw std::runtime_error(SDL_GetError());
            }
        }
    }
}

window::window(glm::ivec2 size)
    : size_(size)
    , good_(false)
{
    detail::init_sdl2_if_not_already();

    //SDL_GL_SetAttribute(SDL_GL_RED_SIZE, context_attributes_.red);
    //SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, context_attributes_.green);
    //SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, context_attributes_.blue);
    //SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, context_attributes_.alpha);
    //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, context_attributes_.depth);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
    //SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, context_attributes_.stencil);

    //if(context_attributes_.samples > 0) {
    //    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
    //    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, context_attributes_.samples);
    //}

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);

    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, context_attributes_.major);
    //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, context_attributes_.minor);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
    // TODO disable this in production.
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);

    //if(context_attributes_.core_profile)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);

    window_ = SDL_CreateWindow(title_.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, size_.x, size_.y, SDL_WINDOW_OPENGL); //| SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS
    if (!window_)
        throw std::runtime_error(SDL_GetError());

    gl_context_ = SDL_GL_CreateContext(window_);
    if (!gl_context_)
        throw std::runtime_error(SDL_GetError());

    SDL_GL_MakeCurrent(window_, gl_context_);

    SDL_GL_SetSwapInterval(0); //context_attributes_.vsync

    good_ = true;
    detail::created_windows[SDL_GetWindowID(window_)] = this;
}

window::~window()
{
    good_ = false;

    if (gl_context_) {
        SDL_GL_DeleteContext(gl_context_);
        gl_context_ = nullptr;
    }

    if (window_) {
        SDL_DestroyWindow(window_);
        window_ = nullptr;
    }
}

glm::ivec2 window::size()
{
    return size_;
}

bool window::good()
{
    /*SDL_Event event;
    while (SDL_PollEvent(&event) != 0) {
        switch (event.type) {
        case SDL_WINDOWEVENT: {
            auto event_window = detail::created_windows[event.window.windowID];
            switch (event.window.event) {
            case SDL_WINDOWEVENT_CLOSE:
                event_window->good_ = false;
                event_window->close();
                break;
            }
            break;
        }
        }
    }*/

    return good_;
}

void window::close()
{
    good_ = false;
}
}
<|endoftext|>


<commit_before>#include "chunk.hpp"
#include <iostream>

using namespace ei;

namespace bim {

	void Chunk::computeTangentSpace(Property::Val _components)
	{
		// Either compute normals only or compute the entire tangent space,
		// orthonormalize and discard the unwanted.
		// For quaternions the entire space is computed and then converted.
		bool needsAll = (_components & Property::QORMAL) || (_components & Property::TANGENT) || (m_properties & Property::BITANGENT);
		bool useTexCoords = needsAll;
		bool computeNormal = (_components & Property::NORMAL) || (needsAll && !(m_properties & Property::NORMAL));
		// Positions and texture coordinates are required for tangent space calculation.
		if(needsAll && !((m_properties & Property::TEXCOORD0) && (m_properties & Property::POSITION))) {
			if(m_properties & Property::POSITION)
			{
				// If not existent compute the normals as usual and the other things as defaults.
				useTexCoords = false;
			} else {
				std::cerr << "Can't compute tangent space. Texture coordinates missing.\n";
				return;
			}
		}

		// Zero all required ones
		if(computeNormal) swap(m_normals, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
		if(needsAll) {
			swap(m_tangents, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
			swap(m_bitangents, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
		}
		if(_components & Property::QORMAL) swap(m_qormals, std::vector<Quaternion>(m_positions.size(), qidentity()));

		// Get tangent spaces on triangles and average them on vertex locations
		if(computeNormal || useTexCoords)
		for(size_t i = 0; i < m_triangles.size(); ++i)
		{
			Vec3 e0 = m_positions[m_triangles[i].y] - m_positions[m_triangles[i].x];
			Vec3 e1 = m_positions[m_triangles[i].z] - m_positions[m_triangles[i].x];
			Vec3 e2 = m_positions[m_triangles[i].z] - m_positions[m_triangles[i].y];
			Vec3 triNormal, triTangent, triBitangent;
			triNormal = normalize(cross(e0, e1));
			eiAssert(all(triNormal == triNormal), "NaN in normal computation!");
			if(useTexCoords) {
				Vec2 uva = m_texCoords0[m_triangles[i].y] - m_texCoords0[m_triangles[i].x];
				Vec2 uvb = m_texCoords0[m_triangles[i].z] - m_texCoords0[m_triangles[i].x];
				float det = uva.x * uvb.y - uva.y * uvb.x; // may swap the sign
				if(det == 0.0f) det = 1.0f;
				triTangent = (uvb.y * e0 - uva.y * e1) / det;
				triBitangent = (uva.x * e1 - uvb.x * e0) / det;
				// Try to recover direction if it got NaN
				bool invalidTangent = !all(triTangent == triTangent) || len(triTangent) < 1e-10f;
				bool invalidBitangent = !all(triBitangent == triBitangent) || len(triBitangent) < 1e-10f;
				if(invalidTangent && invalidBitangent)
				{
					// Create a random orthonormal basis (no uv given)
					triTangent = Vec3(1.0f, triNormal.x, 0.0f);
					triBitangent = Vec3(0.0f, triNormal.z, 1.0f);
				} else if(invalidTangent)
					triTangent = cross(triBitangent, triNormal) * det;
				else if(invalidBitangent)
						triBitangent = cross(triNormal, triTangent) * det;
				if(!ei::orthonormalize(triNormal, triTangent, triBitangent))
					triBitangent = cross(triNormal, triTangent);
				eiAssert(all(triTangent == triTangent), "NaN in tangent computation!");
				eiAssert(all(triBitangent == triBitangent), "NaN in bitangent computation!");
				eiAssert(approx(len(triTangent), 1.0f, 1e-4f), "Computed tangent has a wrong length!");
				eiAssert(approx(len(triBitangent), 1.0f, 1e-4f), "Computed bitangent has a wrong length!");
			}
			float lenE0 = len(e0), lenE1 = len(e1), lenE2 = len(e2);
			float weight = acos(saturate(dot(e0, e1) / (lenE0 * lenE1)));
			if(computeNormal) m_normals[m_triangles[i].x] += triNormal * weight;
			if(useTexCoords) m_tangents[m_triangles[i].x] += triTangent * weight;
			if(useTexCoords) m_bitangents[m_triangles[i].x] += triBitangent * weight;
			weight = acos(saturate(-dot(e0, e2) / (lenE0 * lenE2)));
			if(computeNormal) m_normals[m_triangles[i].y] += triNormal * weight;
			if(useTexCoords) m_tangents[m_triangles[i].y] += triTangent * weight;
			if(useTexCoords) m_bitangents[m_triangles[i].y] += triBitangent * weight;
			weight = acos(saturate(dot(e1, e2) / (lenE1 * lenE2)));
			if(computeNormal) m_normals[m_triangles[i].z] += triNormal * weight;
			if(useTexCoords) m_tangents[m_triangles[i].z] += triTangent * weight;
			if(useTexCoords) m_bitangents[m_triangles[i].z] += triBitangent * weight;
		}

		// Orthonormalize
		if(useTexCoords)
			for(size_t i = 0; i < m_normals.size(); ++i)
				ei::orthonormalize(m_normals[i], m_tangents[i], m_bitangents[i]);
		else if(computeNormal)
			for(size_t i = 0; i < m_normals.size(); ++i)
				m_normals[i] = normalize(m_normals[i]);

		// Generate some "random" tangent spaces without the need of texture coordinates.
		if(needsAll && !useTexCoords)
		{
			for(size_t i = 0; i < m_normals.size(); ++i)
			{
				Mat3x3 m = ei::basis(m_normals[i]);
				m_tangents[i] = ei::Vec3(m.m10, m.m11, m.m12);
				m_bitangents[i] = ei::Vec3(m.m20, m.m21, m.m22);
			}
		}

		// Compute qormals by conversion
		if(_components & Property::QORMAL)
			for(size_t i = 0; i < m_normals.size(); ++i)
				m_qormals[i] = Quaternion(m_normals[i], m_tangents[i], m_bitangents[i]);

		// Discard all the undesired properties for size reasons.
		if(!(_components & Property::NORMAL) && !(m_properties & Property::NORMAL)) swap(m_normals, std::vector<Vec3>());
		if(!(_components & Property::TANGENT) && !(m_properties & Property::TANGENT)) swap(m_tangents, std::vector<Vec3>());
		if(!(_components & Property::BITANGENT) && !(m_properties & Property::BITANGENT)) swap(m_bitangents, std::vector<Vec3>());
		if(!(_components & Property::QORMAL) && !(m_properties & Property::QORMAL)) swap(m_qormals, std::vector<Quaternion>());

		// Update flags
		m_properties = Property::Val(m_properties | _components);
	}

	void Chunk::flipNormals()
	{
		for(size_t i = 0; i < m_normals.size(); ++i)
			m_normals[i] = -m_normals[i];

		// TODO: flip Qormals too
	}

	void Chunk::unifyQormals()
	{
	}

} // namespace bim<commit_msg>more robust tangent space computation (can partially ignore invalid triangles)<commit_after>#include "chunk.hpp"
#include <iostream>

using namespace ei;

namespace bim {

	void Chunk::computeTangentSpace(Property::Val _components)
	{
		// Either compute normals only or compute the entire tangent space,
		// orthonormalize and discard the unwanted.
		// For quaternions the entire space is computed and then converted.
		bool needsAll = (_components & Property::QORMAL) || (_components & Property::TANGENT) || (m_properties & Property::BITANGENT);
		bool useTexCoords = needsAll;
		bool computeNormal = (_components & Property::NORMAL) || (needsAll && !(m_properties & Property::NORMAL));
		// Positions and texture coordinates are required for tangent space calculation.
		if(needsAll && !((m_properties & Property::TEXCOORD0) && (m_properties & Property::POSITION))) {
			if(m_properties & Property::POSITION)
			{
				// If not existent compute the normals as usual and the other things as defaults.
				useTexCoords = false;
			} else {
				std::cerr << "Can't compute tangent space. Texture coordinates missing.\n";
				return;
			}
		}

		// Zero all required ones
		if(computeNormal) swap(m_normals, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
		if(needsAll) {
			swap(m_tangents, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
			swap(m_bitangents, std::vector<Vec3>(m_positions.size(), Vec3(0.0f)));
		}
		if(_components & Property::QORMAL) swap(m_qormals, std::vector<Quaternion>(m_positions.size(), qidentity()));

		// Get tangent spaces on triangles and average them on vertex locations
		if(computeNormal || useTexCoords)
		for(size_t i = 0; i < m_triangles.size(); ++i)
		{
			Vec3 e0 = m_positions[m_triangles[i].y] - m_positions[m_triangles[i].x];
			Vec3 e1 = m_positions[m_triangles[i].z] - m_positions[m_triangles[i].x];
			Vec3 e2 = m_positions[m_triangles[i].z] - m_positions[m_triangles[i].y];
			Vec3 triNormal, triTangent, triBitangent;
			triNormal = normalize(cross(e0, e1));
			// If there are invalid triangles (cause NaN) skip them
			if(all(triNormal == triNormal))
			{
				if(useTexCoords) {
					Vec2 uva = m_texCoords0[m_triangles[i].y] - m_texCoords0[m_triangles[i].x];
					Vec2 uvb = m_texCoords0[m_triangles[i].z] - m_texCoords0[m_triangles[i].x];
					float det = uva.x * uvb.y - uva.y * uvb.x; // may swap the sign
					if(det == 0.0f) det = 1.0f;
					triTangent = (uvb.y * e0 - uva.y * e1) / det;
					triBitangent = (uva.x * e1 - uvb.x * e0) / det;
					// Try to recover direction if it got NaN
					bool invalidTangent = !all(triTangent == triTangent) || len(triTangent) < 1e-10f;
					bool invalidBitangent = !all(triBitangent == triBitangent) || len(triBitangent) < 1e-10f;
					if(invalidTangent && invalidBitangent)
					{
						// Create a random orthonormal basis (no uv given)
						triTangent = Vec3(1.0f, triNormal.x, 0.0f);
						triBitangent = Vec3(0.0f, triNormal.z, 1.0f);
					} else if(invalidTangent)
						triTangent = cross(triBitangent, triNormal) * det;
					else if(invalidBitangent)
							triBitangent = cross(triNormal, triTangent) * det;
					if(!ei::orthonormalize(triNormal, triTangent, triBitangent))
						triBitangent = cross(triNormal, triTangent);
					eiAssert(all(triTangent == triTangent), "NaN in tangent computation!");
					eiAssert(all(triBitangent == triBitangent), "NaN in bitangent computation!");
					eiAssert(approx(len(triTangent), 1.0f, 1e-4f), "Computed tangent has a wrong length!");
					eiAssert(approx(len(triBitangent), 1.0f, 1e-4f), "Computed bitangent has a wrong length!");
				}
				float lenE0 = len(e0), lenE1 = len(e1), lenE2 = len(e2);
				float weight = acos(saturate(dot(e0, e1) / (lenE0 * lenE1)));
				eiAssert(weight == weight, "weight is NaN");
				if(computeNormal) m_normals[m_triangles[i].x] += triNormal * weight;
				if(useTexCoords) m_tangents[m_triangles[i].x] += triTangent * weight;
				if(useTexCoords) m_bitangents[m_triangles[i].x] += triBitangent * weight;
				weight = acos(saturate(-dot(e0, e2) / (lenE0 * lenE2)));
				eiAssert(weight == weight, "weight is NaN");
				if(computeNormal) m_normals[m_triangles[i].y] += triNormal * weight;
				if(useTexCoords) m_tangents[m_triangles[i].y] += triTangent * weight;
				if(useTexCoords) m_bitangents[m_triangles[i].y] += triBitangent * weight;
				weight = acos(saturate(dot(e1, e2) / (lenE1 * lenE2)));
				eiAssert(weight == weight, "weight is NaN");
				if(computeNormal) m_normals[m_triangles[i].z] += triNormal * weight;
				if(useTexCoords) m_tangents[m_triangles[i].z] += triTangent * weight;
				if(useTexCoords) m_bitangents[m_triangles[i].z] += triBitangent * weight;
			}
		}

		// Orthonormalize
		if(useTexCoords)
			for(size_t i = 0; i < m_normals.size(); ++i)
				ei::orthonormalize(m_normals[i], m_tangents[i], m_bitangents[i]);
		else if(computeNormal)
			for(size_t i = 0; i < m_normals.size(); ++i)
			{
				float length = len(m_normals[i]);
				if(length > 0.0f)
					m_normals[i] /= length;
			}

		// Generate some "random" tangent spaces without the need of texture coordinates.
		if(needsAll && !useTexCoords)
		{
			for(size_t i = 0; i < m_normals.size(); ++i)
			{
				Mat3x3 m = ei::basis(m_normals[i]);
				m_tangents[i] = ei::Vec3(m.m10, m.m11, m.m12);
				m_bitangents[i] = ei::Vec3(m.m20, m.m21, m.m22);
			}
		}

		// Compute qormals by conversion
		if(_components & Property::QORMAL)
			for(size_t i = 0; i < m_normals.size(); ++i)
				m_qormals[i] = Quaternion(m_normals[i], m_tangents[i], m_bitangents[i]);

		// Discard all the undesired properties for size reasons.
		if(!(_components & Property::NORMAL) && !(m_properties & Property::NORMAL)) swap(m_normals, std::vector<Vec3>());
		if(!(_components & Property::TANGENT) && !(m_properties & Property::TANGENT)) swap(m_tangents, std::vector<Vec3>());
		if(!(_components & Property::BITANGENT) && !(m_properties & Property::BITANGENT)) swap(m_bitangents, std::vector<Vec3>());
		if(!(_components & Property::QORMAL) && !(m_properties & Property::QORMAL)) swap(m_qormals, std::vector<Quaternion>());

		// Update flags
		m_properties = Property::Val(m_properties | _components);
	}

	void Chunk::flipNormals()
	{
		for(size_t i = 0; i < m_normals.size(); ++i)
			m_normals[i] = -m_normals[i];

		// TODO: flip Qormals too
	}

	void Chunk::unifyQormals()
	{
	}

} // namespace bim<|endoftext|>


<commit_before>#include "task_manager.hpp"

namespace TaskDistribution {
  /*TaskManager::TaskManager():
    next_free_obj_id_(1) { }

  TaskManager::~TaskManager() {
    for (auto& it : hash_map_)
      delete it.second;
  }

  void TaskManager::check_if_ready(ArchiveKey const& task_key) {
    TaskEntry task_entry;
    archive_.load(task_key, task_entry, true);

    if (task_entry.result.is_valid() || !task_entry.should_save)
      return;

    BaseTask *task;
    archive_.load(task_entry.task, task, true);

    if (task->parents_active_ == 0)
        tasks_ready_to_run_.insert(task_key);

    delete task;
  }*/

  /*void TaskManager::run() {
#if !(NO_MPI)
    if (world_.size() > 1) {
      if (world_.rank() == 0)
        run_manager();
      else
        run_others();
    } else
#endif
      run_single();
  }

#if !(NO_MPI)
  void TaskManager::run_manager() {
    bool node_free[world_.size()-1];

    for (int i = 0; i < world_.size()-1; i++)
      node_free[i] = true;

    size_t n_running = 0;
    size_t current = 0;

    while (!free_.empty() || n_running != 0) {
      print_status();

      if (free_.empty() || n_running == world_.size()-1) {
        auto status = world_.probe();
        size_t task_hash;
        world_.recv(status.source(), 0, task_hash);

        BaseTask* task = hash_map_.at(task_hash);
        task->receive_value(world_, status.source());

        n_running--;
        node_free[status.source()-1] = true;
        current = status.source()-1;

        task_completed(task);
      }

      if (!free_.empty()) {
        BaseTask* t = free_.front();
        free_.pop_front();

        if (t->run_locally()) {
          t->compute();
          task_completed(t);
        } else {
          while (!node_free[current])
            current = (current+1) % (world_.size()-1);

          if (t->assign(world_, current+1)) {
            n_running++;
            node_free[current] = false;
          }
        }
      }
    }

    size_t invalid_hash = BaseComputingUnit::get_invalid_id();

    // Make other process end
    for (int i = 1; i < world_.size(); i++)
      world_.send(i, 0, invalid_hash);
  }

  void TaskManager::run_others() {
    while (1) {
      size_t callable_hash;
      world_.recv(0, 0, callable_hash);
      BaseComputingUnit const* callable = BaseComputingUnit::get_by_id(callable_hash);

      if (!callable)
        break;

      callable->execute(world_);
    }
  }
#endif*/

  void TaskManager::run_single() {
    while (!ready_.empty()) {
      //print_status();
      Key task_key = ready_.front();
      ready_.pop_front();
      TaskEntry entry;
      archive_.load(task_key, entry);
      unit_manager_.process_local(entry);
      task_completed(task_key);
    }
  }

  void TaskManager::task_completed(Key const& task_key) {
    for (auto& child_key: map_task_to_children_.at(task_key)) {
      map_key_to_task_.at(child_key)->parents_active_--;
      if (map_key_to_task_.at(child_key)->parents_active_ == 0)
        ready_.push_back(child_key);
    }

    for (auto& parent_key: map_task_to_parents_.at(task_key))
      map_key_to_task_.at(parent_key)->children_active_--;

    //if (task->should_save())
    //  count_map_.at(task->get_name()).second++;
  }

  /*void TaskManager::unload(BaseTask *task) {
    task->unload();

    for (auto& it: task->parents_) {
      it->children_active_--;
      if (it->children_active_ == 0)
        unload(it);
    }
  }

  BaseTask* TaskManager::get(size_t hash) const {
    if (hash_map_.find(hash) != hash_map_.end())
      return hash_map_.at(hash);

    return nullptr;
  }

  void TaskManager::insert(size_t hash, std::string name, BaseTask* t) {
    hash_map_[hash] = t;
    name_map_[name].push_back(hash);

    if (t->should_save()) {
      if (count_map_.find(name) == count_map_.end())
        count_map_[name] = std::pair<size_t,size_t>(1, check(t));
      else {
        count_map_[name].first++;
        count_map_[name].second += check(t);
      }
    }
  }

  bool TaskManager::check(BaseTask* t) const {
    return archive_.is_available(t->get_id());
  }*/

  /*size_t TaskManager::id() const {
#if ENABLE_MPI
    return world_.rank();
#else
    return 0;
#endif
  }*/

  /*void TaskManager::print_status() {
    time_t current = time(NULL);

    if (current == last_print_)
      return;

    last_print_ = current;

    size_t descriptor_len = 9, number_len = 8;

    for (auto& it: count_map_) {
      descriptor_len = std::max(descriptor_len, it.first.length());
      size_t len = 0, size = it.second.first;

      while (size) {
        len += 1;
        size /= 10;
      }

      if (len == 0) len = 1;

      number_len = std::max(number_len, len);
    }

    size_t padding = 4;
    std::string padding_str(padding, ' ');

    size_t total_line_width = descriptor_len + number_len*2 + padding*2;

    std::cout << "Task name" <<
      std::string(descriptor_len-strlen("Task name"),' ') << padding_str <<
      " Waiting" << padding_str << "Finished" << std::endl;
    std::cout << std::string(total_line_width, '-') << std::endl;

    for (auto& it: count_map_) {
      size_t finished = it.second.second;
      size_t waiting = it.second.first - finished;

      char waiting_str[number_len], finished_str[number_len];
      sprintf(waiting_str, "%*lu", (int)number_len, waiting);
      sprintf(finished_str, "%*lu", (int)number_len, finished);

      std::cout << it.first << std::string(descriptor_len-it.first.length(),' ');
      std::cout << padding_str << waiting_str;
      std::cout << padding_str << finished_str;
      std::cout << std::endl;
    }

    std::cout << std::endl;
  }

  void TaskManager::invalidate(std::string name) {
    if (name_map_.find(name) == name_map_.end())
      return;

    for (auto& hash: name_map_.at(name))
      invalidate(get(hash));
  }

  void TaskManager::invalidate(BaseTask* task) {
    if (task->on_disk_) {
      task->on_disk_ = false;
      size_t id = task->get_id();
      archive_.remove(id);

      count_map_.at(task->get_name()).second--;
    }

    // Invalidate all others that depend on this one
    for (auto& it: task->children_)
      invalidate(it);
  }

  void TaskManager::clean() {
    archive_.clear();
  }*/

  /*ArchiveKey TaskManager::new_object_key() {
    ArchiveKey key;
    key.node_id = id();
    key.obj_id = next_free_obj_id_++;
    return key;
  }

  ArchiveKey TaskManager::get_task(std::string const& unit_key,
      std::string const& args_key,
      std::string const& unit_str,
      std::string const& args_str) {
    std::string map_key = unit_key + args_key;

    ArchiveKey task_key;
    bool found_previous_task = false;

    if (map_typenames_to_tasks_.count(map_key) > 0) {
      auto range = map_typenames_to_tasks_.equal_range(map_key);
      for (auto it = range.first;
          it != range.second && !found_previous_task;
          ++it) {
        task_key = it->second;
        TaskEntry task_entry;
        archive_.load(task_key, task_entry, false);

        std::string data;

        archive_.load_raw(task_entry.computing_unit, data, false);
        if (data != unit_str)
          continue;

        archive_.load_raw(task_entry.arguments, data, false);
        if (data != args_str)
          continue;

        found_previous_task = true;
      }
    }

    if (!found_previous_task) {
      task_key = new_object_key();
      TaskEntry task_entry;

      task_entry.computing_unit =
        get_component(unit_key, unit_str, map_unit_names_to_units_);
      task_entry.arguments =
        get_component(args_key, args_str, map_arg_names_to_args_);

      archive_.insert(task_key, task_entry, true);
      map_typenames_to_tasks_.insert({map_key, task_key});
    }

    return task_key;
  }

  ArchiveKey TaskManager::get_component(std::string const& map_key,
          std::string const& str,
          std::unordered_multimap<std::string, ArchiveKey>& map) {
    ArchiveKey key;
    bool found_previous = false;

    if (map.count(map_key) > 0) {
      auto range = map.equal_range(map_key);
      for (auto it = range.first;
          it != range.second && !found_previous;
          ++it) {
        key = it->second;

        std::string data;

        archive_.load_raw(key, data, false);
        if (data != str)
          continue;

        found_previous = true;
      }
    }

    if (!found_previous) {
      key = new_object_key();
      archive_.insert_raw(key, str, false);
      map.insert({map_key, key});
    }

    return key;
  }*/

  Key TaskManager::new_key(Key::Type type) {
    return
#if ENABLE_MPI
      Key::new_key(world_, type);
#else
      Key::new_key(type);
#endif
  }

  void TaskManager::create_family_lists(TaskEntry& entry) {
    if (!entry.parents_key.is_valid()) {
      entry.parents_key = new_key(Key::Parents);
      archive_.insert(entry.parents_key, KeySet());
    }

    if (!entry.children_key.is_valid()) {
      entry.children_key = new_key(Key::Children);
      archive_.insert(entry.children_key, KeySet());
    }
  }

  void TaskManager::add_dependency(BaseTask* child,
      TaskEntry const& child_entry, Key const& parent_key, KeySet& parents) {
    BaseTask* parent = map_key_to_task_.at(parent_key);

    TaskEntry parent_entry;
    archive_.load(parent_key, parent_entry);

    KeySet children;
    archive_.load(parent_entry.children_key, children);

    // Creates bidirectional maps
    map_task_to_parents_[child_entry.task_key].insert(parent_key);
    map_task_to_children_[parent_key].insert(child_entry.task_key);

    parents.insert(parent_key);
    children.insert(child_entry.task_key);

    archive_.insert(parent_entry.children_key, children);

    if (!parent_entry.result_key.is_valid() && parent_entry.should_save)
      child->parents_active_++;
    if (!child_entry.result_key.is_valid() && child_entry.should_save)
      parent->children_active_++;
  }
};
<commit_msg>Fixed bug with tasks that don't have children or parents.<commit_after>#include "task_manager.hpp"

namespace TaskDistribution {
  /*TaskManager::TaskManager():
    next_free_obj_id_(1) { }

  TaskManager::~TaskManager() {
    for (auto& it : hash_map_)
      delete it.second;
  }

  void TaskManager::check_if_ready(ArchiveKey const& task_key) {
    TaskEntry task_entry;
    archive_.load(task_key, task_entry, true);

    if (task_entry.result.is_valid() || !task_entry.should_save)
      return;

    BaseTask *task;
    archive_.load(task_entry.task, task, true);

    if (task->parents_active_ == 0)
        tasks_ready_to_run_.insert(task_key);

    delete task;
  }*/

  /*void TaskManager::run() {
#if !(NO_MPI)
    if (world_.size() > 1) {
      if (world_.rank() == 0)
        run_manager();
      else
        run_others();
    } else
#endif
      run_single();
  }

#if !(NO_MPI)
  void TaskManager::run_manager() {
    bool node_free[world_.size()-1];

    for (int i = 0; i < world_.size()-1; i++)
      node_free[i] = true;

    size_t n_running = 0;
    size_t current = 0;

    while (!free_.empty() || n_running != 0) {
      print_status();

      if (free_.empty() || n_running == world_.size()-1) {
        auto status = world_.probe();
        size_t task_hash;
        world_.recv(status.source(), 0, task_hash);

        BaseTask* task = hash_map_.at(task_hash);
        task->receive_value(world_, status.source());

        n_running--;
        node_free[status.source()-1] = true;
        current = status.source()-1;

        task_completed(task);
      }

      if (!free_.empty()) {
        BaseTask* t = free_.front();
        free_.pop_front();

        if (t->run_locally()) {
          t->compute();
          task_completed(t);
        } else {
          while (!node_free[current])
            current = (current+1) % (world_.size()-1);

          if (t->assign(world_, current+1)) {
            n_running++;
            node_free[current] = false;
          }
        }
      }
    }

    size_t invalid_hash = BaseComputingUnit::get_invalid_id();

    // Make other process end
    for (int i = 1; i < world_.size(); i++)
      world_.send(i, 0, invalid_hash);
  }

  void TaskManager::run_others() {
    while (1) {
      size_t callable_hash;
      world_.recv(0, 0, callable_hash);
      BaseComputingUnit const* callable = BaseComputingUnit::get_by_id(callable_hash);

      if (!callable)
        break;

      callable->execute(world_);
    }
  }
#endif*/

  void TaskManager::run_single() {
    while (!ready_.empty()) {
      //print_status();
      Key task_key = ready_.front();
      ready_.pop_front();
      TaskEntry entry;
      archive_.load(task_key, entry);
      unit_manager_.process_local(entry);
      task_completed(task_key);
    }
  }

  void TaskManager::task_completed(Key const& task_key) {
    {
      auto it = map_task_to_children_.find(task_key);
      if (it != map_task_to_children_.end()) {
        for (auto& child_key: it->second) {
          map_key_to_task_.at(child_key)->parents_active_--;
          if (map_key_to_task_.at(child_key)->parents_active_ == 0)
            ready_.push_back(child_key);
        }
      }
    }

    {
      auto it = map_task_to_parents_.find(task_key);
      if (it != map_task_to_parents_.end()) {
        for (auto& parent_key: it->second)
          map_key_to_task_.at(parent_key)->children_active_--;
      }
    }

    //if (task->should_save())
    //  count_map_.at(task->get_name()).second++;
  }

  /*void TaskManager::unload(BaseTask *task) {
    task->unload();

    for (auto& it: task->parents_) {
      it->children_active_--;
      if (it->children_active_ == 0)
        unload(it);
    }
  }

  BaseTask* TaskManager::get(size_t hash) const {
    if (hash_map_.find(hash) != hash_map_.end())
      return hash_map_.at(hash);

    return nullptr;
  }

  void TaskManager::insert(size_t hash, std::string name, BaseTask* t) {
    hash_map_[hash] = t;
    name_map_[name].push_back(hash);

    if (t->should_save()) {
      if (count_map_.find(name) == count_map_.end())
        count_map_[name] = std::pair<size_t,size_t>(1, check(t));
      else {
        count_map_[name].first++;
        count_map_[name].second += check(t);
      }
    }
  }

  bool TaskManager::check(BaseTask* t) const {
    return archive_.is_available(t->get_id());
  }*/

  /*size_t TaskManager::id() const {
#if ENABLE_MPI
    return world_.rank();
#else
    return 0;
#endif
  }*/

  /*void TaskManager::print_status() {
    time_t current = time(NULL);

    if (current == last_print_)
      return;

    last_print_ = current;

    size_t descriptor_len = 9, number_len = 8;

    for (auto& it: count_map_) {
      descriptor_len = std::max(descriptor_len, it.first.length());
      size_t len = 0, size = it.second.first;

      while (size) {
        len += 1;
        size /= 10;
      }

      if (len == 0) len = 1;

      number_len = std::max(number_len, len);
    }

    size_t padding = 4;
    std::string padding_str(padding, ' ');

    size_t total_line_width = descriptor_len + number_len*2 + padding*2;

    std::cout << "Task name" <<
      std::string(descriptor_len-strlen("Task name"),' ') << padding_str <<
      " Waiting" << padding_str << "Finished" << std::endl;
    std::cout << std::string(total_line_width, '-') << std::endl;

    for (auto& it: count_map_) {
      size_t finished = it.second.second;
      size_t waiting = it.second.first - finished;

      char waiting_str[number_len], finished_str[number_len];
      sprintf(waiting_str, "%*lu", (int)number_len, waiting);
      sprintf(finished_str, "%*lu", (int)number_len, finished);

      std::cout << it.first << std::string(descriptor_len-it.first.length(),' ');
      std::cout << padding_str << waiting_str;
      std::cout << padding_str << finished_str;
      std::cout << std::endl;
    }

    std::cout << std::endl;
  }

  void TaskManager::invalidate(std::string name) {
    if (name_map_.find(name) == name_map_.end())
      return;

    for (auto& hash: name_map_.at(name))
      invalidate(get(hash));
  }

  void TaskManager::invalidate(BaseTask* task) {
    if (task->on_disk_) {
      task->on_disk_ = false;
      size_t id = task->get_id();
      archive_.remove(id);

      count_map_.at(task->get_name()).second--;
    }

    // Invalidate all others that depend on this one
    for (auto& it: task->children_)
      invalidate(it);
  }

  void TaskManager::clean() {
    archive_.clear();
  }*/

  /*ArchiveKey TaskManager::new_object_key() {
    ArchiveKey key;
    key.node_id = id();
    key.obj_id = next_free_obj_id_++;
    return key;
  }

  ArchiveKey TaskManager::get_task(std::string const& unit_key,
      std::string const& args_key,
      std::string const& unit_str,
      std::string const& args_str) {
    std::string map_key = unit_key + args_key;

    ArchiveKey task_key;
    bool found_previous_task = false;

    if (map_typenames_to_tasks_.count(map_key) > 0) {
      auto range = map_typenames_to_tasks_.equal_range(map_key);
      for (auto it = range.first;
          it != range.second && !found_previous_task;
          ++it) {
        task_key = it->second;
        TaskEntry task_entry;
        archive_.load(task_key, task_entry, false);

        std::string data;

        archive_.load_raw(task_entry.computing_unit, data, false);
        if (data != unit_str)
          continue;

        archive_.load_raw(task_entry.arguments, data, false);
        if (data != args_str)
          continue;

        found_previous_task = true;
      }
    }

    if (!found_previous_task) {
      task_key = new_object_key();
      TaskEntry task_entry;

      task_entry.computing_unit =
        get_component(unit_key, unit_str, map_unit_names_to_units_);
      task_entry.arguments =
        get_component(args_key, args_str, map_arg_names_to_args_);

      archive_.insert(task_key, task_entry, true);
      map_typenames_to_tasks_.insert({map_key, task_key});
    }

    return task_key;
  }

  ArchiveKey TaskManager::get_component(std::string const& map_key,
          std::string const& str,
          std::unordered_multimap<std::string, ArchiveKey>& map) {
    ArchiveKey key;
    bool found_previous = false;

    if (map.count(map_key) > 0) {
      auto range = map.equal_range(map_key);
      for (auto it = range.first;
          it != range.second && !found_previous;
          ++it) {
        key = it->second;

        std::string data;

        archive_.load_raw(key, data, false);
        if (data != str)
          continue;

        found_previous = true;
      }
    }

    if (!found_previous) {
      key = new_object_key();
      archive_.insert_raw(key, str, false);
      map.insert({map_key, key});
    }

    return key;
  }*/

  Key TaskManager::new_key(Key::Type type) {
    return
#if ENABLE_MPI
      Key::new_key(world_, type);
#else
      Key::new_key(type);
#endif
  }

  void TaskManager::create_family_lists(TaskEntry& entry) {
    if (!entry.parents_key.is_valid()) {
      entry.parents_key = new_key(Key::Parents);
      archive_.insert(entry.parents_key, KeySet());
    }

    if (!entry.children_key.is_valid()) {
      entry.children_key = new_key(Key::Children);
      archive_.insert(entry.children_key, KeySet());
    }
  }

  void TaskManager::add_dependency(BaseTask* child,
      TaskEntry const& child_entry, Key const& parent_key, KeySet& parents) {
    BaseTask* parent = map_key_to_task_.at(parent_key);

    TaskEntry parent_entry;
    archive_.load(parent_key, parent_entry);

    KeySet children;
    archive_.load(parent_entry.children_key, children);

    // Creates bidirectional maps
    map_task_to_parents_[child_entry.task_key].insert(parent_key);
    map_task_to_children_[parent_key].insert(child_entry.task_key);

    parents.insert(parent_key);
    children.insert(child_entry.task_key);

    archive_.insert(parent_entry.children_key, children);

    if (!parent_entry.result_key.is_valid() && parent_entry.should_save)
      child->parents_active_++;
    if (!child_entry.result_key.is_valid() && child_entry.should_save)
      parent->children_active_++;
  }
};
<|endoftext|>


<commit_before>#ifndef TEST__MODELS__UTILITY_HPP
#define TEST__MODELS__UTILITY_HPP

#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <stdexcept>

namespace cmdstan {
namespace test {

// only counts non-overlapping matches;  after match, advances to
// end of match;
// empty target returns -1
int count_matches(const std::string &target, const std::string &s) {
  if (target.size() == 0)
    return -1;  // error
  int count = 0;
  for (size_t pos = 0; (pos = s.find(target, pos)) != std::string::npos;
       pos += target.size())
    ++count;
  return count;
}

/**
 * Gets the path separator for the OS.
 *
 * @return '\' for Windows, '/' otherwise.
 */
char get_path_separator() {
#if defined(WIN32) || defined(_WIN32) \
    || defined(__WIN32) && !defined(__CYGWIN__)
  static char path_separator = '\\';
#else
  static char path_separator = '/';
#endif
  return path_separator;
}

/**
 * Multiple command separator
 *
 * @return '&' for Windows, ';' otherwise.
 */
char multiple_command_separator() {
  if (get_path_separator() == '/')
    return ';';
  else
    return '&';
}

/**
 * Returns the path as a string with the appropriate
 * path separator.
 *
 * @param model_path vector of strings representing path to the model
 *
 * @return the string representation of the path with the appropriate
 *    path separator.
 */
std::string convert_model_path(const std::vector<std::string> &model_path) {
  std::string path;
  if (model_path.size() > 0) {
    path.append(model_path[0]);
    for (size_t i = 1; i < model_path.size(); i++) {
      path.append(1, get_path_separator());
      path.append(model_path[i]);
    }
  }
  return path;
}

struct run_command_output {
  std::string command;
  std::string output;
  long time;
  int err_code;
  bool hasError;
  std::string header;
  std::string body;

  run_command_output(const std::string command, const std::string output,
                     const long time, const int err_code)
      : command(command),
        output(output),
        time(time),
        err_code(err_code),
        hasError(err_code != 0),
        header(),
        body() {
    size_t end_of_header = output.find("\n\n");
    if (end_of_header == std::string::npos)
      end_of_header = 0;
    else
      end_of_header += 2;
    header = output.substr(0, end_of_header);
    body = output.substr(end_of_header);
  }

  run_command_output()
      : command(),
        output(),
        time(0),
        err_code(0),
        hasError(false),
        header(),
        body() {}
};

std::ostream &operator<<(std::ostream &os, const run_command_output &out) {
  os << "run_command output:"
     << "\n"
     << "- command:   " << out.command << "\n"
     << "- output:    " << out.output << "\n"
     << "- time (ms): " << out.time << "\n"
     << "- err_code:  " << out.err_code << "\n"
     << "- hasError:  " << (out.hasError ? "true" : "false") << "\n"
     << "- header:    " << out.header << "\n"
     << "- body:      " << out.body << std::endl;
  return os;
}

/**
 * Runs the command provided and returns the system output
 * as a string.
 *
 * @param command A command that can be run from the shell
 * @return the system output of the command
 */
run_command_output run_command(std::string command) {
  using boost::posix_time::microsec_clock;
  using boost::posix_time::ptime;
  FILE *in;
  in = popen(command.c_str(), "r");

  if (!in) {
    std::string err_msg;
    err_msg = "Fatal error with popen; could not execute: \"";
    err_msg += command;
    err_msg += "\"";
    throw std::runtime_error(err_msg.c_str());
  }

  std::string output;
  char buf[1024];
  size_t count;
  ptime time_start(microsec_clock::universal_time());  // start timer
  while ((count = fread(&buf, 1, 1024, in)) > 0)
    output += std::string(&buf[0], &buf[count]);
  ptime time_end(microsec_clock::universal_time());  // end timer

  // bits 15-8 is err code, bit 7 if core dump, bits 6-0 is signal number
  int err_code = pclose(in);
  // on Windows, err code is the return code.
  if (err_code != 0 && (err_code >> 8) > 0)
    err_code >>= 8;

  return run_command_output(
      command, output, (time_end - time_start).total_milliseconds(), err_code);
}

/**
 * Returns the help options from the string provided.
 * Help options start with "--".
 *
 * @param help_output output from "model/command --help"
 * @return a vector of strings of the help options
 */
std::vector<std::string> parse_help_options(const std::string &help_output) {
  std::vector<std::string> help_options;

  size_t option_start = help_output.find("--");
  while (option_start != std::string::npos) {
    // find the option name (skip two characters for "--")
    option_start += 2;
    size_t option_end = help_output.find_first_of("= ", option_start);
    help_options.push_back(
        help_output.substr(option_start, option_end - option_start));
    option_start = help_output.find("--", option_start + 1);
  }

  return help_options;
}

/**
 * Parses output from a Stan model run from the command line.
 * Returns option, value pairs.
 *
 * @param command_output The output from a Stan model run from the command line.
 *
 * @return Option, value pairs as indicated by the Stan model.
 */
std::vector<std::pair<std::string, std::string>> parse_command_output(
    const std::string &command_output) {
  using std::pair;
  using std::string;
  using std::vector;
  vector<pair<string, string>> output;

  string option, value;
  size_t start = 0, end = command_output.find("\n", start);

  start = end + 1;
  end = command_output.find("\n", start);
  size_t equal_pos = command_output.find("=", start);

  while (equal_pos != string::npos) {
    using boost::trim;
    option = command_output.substr(start, equal_pos - start);
    value = command_output.substr(equal_pos + 1, end - equal_pos - 1);
    trim(option);
    trim(value);
    output.push_back(pair<string, string>(option, value));
    start = end + 1;
    end = command_output.find("\n", start);
    equal_pos = command_output.find("=", start);
  }
  return output;
}

}  // namespace test
}  // namespace cmdstan
#endif
<commit_msg>add vector to test utility<commit_after>#ifndef TEST__MODELS__UTILITY_HPP
#define TEST__MODELS__UTILITY_HPP

#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <stdexcept>
#include <vector>

namespace cmdstan {
namespace test {

// only counts non-overlapping matches;  after match, advances to
// end of match;
// empty target returns -1
int count_matches(const std::string &target, const std::string &s) {
  if (target.size() == 0)
    return -1;  // error
  int count = 0;
  for (size_t pos = 0; (pos = s.find(target, pos)) != std::string::npos;
       pos += target.size())
    ++count;
  return count;
}

/**
 * Gets the path separator for the OS.
 *
 * @return '\' for Windows, '/' otherwise.
 */
char get_path_separator() {
#if defined(WIN32) || defined(_WIN32) \
    || defined(__WIN32) && !defined(__CYGWIN__)
  static char path_separator = '\\';
#else
  static char path_separator = '/';
#endif
  return path_separator;
}

/**
 * Multiple command separator
 *
 * @return '&' for Windows, ';' otherwise.
 */
char multiple_command_separator() {
  if (get_path_separator() == '/')
    return ';';
  else
    return '&';
}

/**
 * Returns the path as a string with the appropriate
 * path separator.
 *
 * @param model_path vector of strings representing path to the model
 *
 * @return the string representation of the path with the appropriate
 *    path separator.
 */
std::string convert_model_path(const std::vector<std::string> &model_path) {
  std::string path;
  if (model_path.size() > 0) {
    path.append(model_path[0]);
    for (size_t i = 1; i < model_path.size(); i++) {
      path.append(1, get_path_separator());
      path.append(model_path[i]);
    }
  }
  return path;
}

struct run_command_output {
  std::string command;
  std::string output;
  long time;
  int err_code;
  bool hasError;
  std::string header;
  std::string body;

  run_command_output(const std::string command, const std::string output,
                     const long time, const int err_code)
      : command(command),
        output(output),
        time(time),
        err_code(err_code),
        hasError(err_code != 0),
        header(),
        body() {
    size_t end_of_header = output.find("\n\n");
    if (end_of_header == std::string::npos)
      end_of_header = 0;
    else
      end_of_header += 2;
    header = output.substr(0, end_of_header);
    body = output.substr(end_of_header);
  }

  run_command_output()
      : command(),
        output(),
        time(0),
        err_code(0),
        hasError(false),
        header(),
        body() {}
};

std::ostream &operator<<(std::ostream &os, const run_command_output &out) {
  os << "run_command output:"
     << "\n"
     << "- command:   " << out.command << "\n"
     << "- output:    " << out.output << "\n"
     << "- time (ms): " << out.time << "\n"
     << "- err_code:  " << out.err_code << "\n"
     << "- hasError:  " << (out.hasError ? "true" : "false") << "\n"
     << "- header:    " << out.header << "\n"
     << "- body:      " << out.body << std::endl;
  return os;
}

/**
 * Runs the command provided and returns the system output
 * as a string.
 *
 * @param command A command that can be run from the shell
 * @return the system output of the command
 */
run_command_output run_command(std::string command) {
  using boost::posix_time::microsec_clock;
  using boost::posix_time::ptime;
  FILE *in;
  in = popen(command.c_str(), "r");

  if (!in) {
    std::string err_msg;
    err_msg = "Fatal error with popen; could not execute: \"";
    err_msg += command;
    err_msg += "\"";
    throw std::runtime_error(err_msg.c_str());
  }

  std::string output;
  char buf[1024];
  size_t count;
  ptime time_start(microsec_clock::universal_time());  // start timer
  while ((count = fread(&buf, 1, 1024, in)) > 0)
    output += std::string(&buf[0], &buf[count]);
  ptime time_end(microsec_clock::universal_time());  // end timer

  // bits 15-8 is err code, bit 7 if core dump, bits 6-0 is signal number
  int err_code = pclose(in);
  // on Windows, err code is the return code.
  if (err_code != 0 && (err_code >> 8) > 0)
    err_code >>= 8;

  return run_command_output(
      command, output, (time_end - time_start).total_milliseconds(), err_code);
}

/**
 * Returns the help options from the string provided.
 * Help options start with "--".
 *
 * @param help_output output from "model/command --help"
 * @return a vector of strings of the help options
 */
std::vector<std::string> parse_help_options(const std::string &help_output) {
  std::vector<std::string> help_options;

  size_t option_start = help_output.find("--");
  while (option_start != std::string::npos) {
    // find the option name (skip two characters for "--")
    option_start += 2;
    size_t option_end = help_output.find_first_of("= ", option_start);
    help_options.push_back(
        help_output.substr(option_start, option_end - option_start));
    option_start = help_output.find("--", option_start + 1);
  }

  return help_options;
}

/**
 * Parses output from a Stan model run from the command line.
 * Returns option, value pairs.
 *
 * @param command_output The output from a Stan model run from the command line.
 *
 * @return Option, value pairs as indicated by the Stan model.
 */
std::vector<std::pair<std::string, std::string>> parse_command_output(
    const std::string &command_output) {
  using std::pair;
  using std::string;
  using std::vector;
  vector<pair<string, string>> output;

  string option, value;
  size_t start = 0, end = command_output.find("\n", start);

  start = end + 1;
  end = command_output.find("\n", start);
  size_t equal_pos = command_output.find("=", start);

  while (equal_pos != string::npos) {
    using boost::trim;
    option = command_output.substr(start, equal_pos - start);
    value = command_output.substr(equal_pos + 1, end - equal_pos - 1);
    trim(option);
    trim(value);
    output.push_back(pair<string, string>(option, value));
    start = end + 1;
    end = command_output.find("\n", start);
    equal_pos = command_output.find("=", start);
  }
  return output;
}

}  // namespace test
}  // namespace cmdstan
#endif
<|endoftext|>


<commit_before>#include "lunar_green_thread.hpp"

#include <iostream>

volatile int n = 0;

void
func3(void *arg) {
    auto ws = (lunar::shared_stream*)arg;
    for (;;) {
        lunar::select_green_thread(nullptr, 0, nullptr, 0, false, 11000);
        auto ret = lunar::push_ptr(ws, nullptr);
        assert(ret == lunar::STRM_SUCCESS);
        fflush(stdout);
    }
}

void
func1(void *arg)
{
    n++;
    while(n != 2); // barrier

    auto rs = new lunar::shared_stream;
    auto ws = new lunar::shared_stream;
    lunar::make_ptr_stream(rs, ws, 1);

    lunar::spawn_green_thread(func3, ws);

#ifdef KQUEUE
    struct kevent kev;
    EV_SET(&kev, STDIN_FILENO, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
#endif // KQUEUE

    printf("> ");
    fflush(stdout);

    for (;;) {
        lunar::select_green_thread(&kev, 1, (void**)&rs, 1, true, 5000);

        if (lunar::is_timeout_green_thread()) {
            printf("timeout!\n> ");
            fflush(stdout);
        }

        if (lunar::is_ready_threadq_green_thread()) {
            void *data;
            auto ret = lunar::pop_threadq_green_thread(&data);
            assert(ret == lunar::STRM_SUCCESS);

            printf("recv thread queue!\n> ");
            fflush(stdout);
        }

        void **streams;
        ssize_t len;
        lunar::get_streams_ready_green_thread(&streams, &len);
        for (int i = 0; i < len; i++) {
            void *val;
            auto ret = lunar::pop_ptr((lunar::shared_stream*)streams[i], &val);
            assert(ret == lunar::STRM_SUCCESS);
            printf("recv stream!\n> ");
            fflush(stdout);
        }

        lunar::fdevent_green_thread *fdev;
        lunar::get_fds_ready_green_thread(&fdev, &len);
        for (int i = 0; i < len; i++) {
            if (fdev[i].fd == STDIN_FILENO && fdev[i].event == FD_EV_READ) {
                std::string s;
                std::cin >> s;
                printf("input = %s\n> ", s.c_str());
                fflush(stdout);
            }
        }
    }
}

void
func2(void *arg)
{
    n++;
    while(n != 2); // barrier

    auto fb = lunar::get_green_thread(1);
    for (;;) {
        lunar::select_green_thread(nullptr, 0, nullptr, 0, false, 13000);
        lunar::push_threadq_fast_unsafe_green_thread(fb, nullptr);
    }
}

void
thread2()
{
    lunar::init_green_thread(2);
    lunar::spawn_green_thread(func2);
    lunar::run_green_thread();
}

void
thread1()
{
    lunar::init_green_thread(1);
    lunar::spawn_green_thread(func1);
    lunar::run_green_thread();
}

int
main(int argc, char *argv[])
{
    std::thread th1(thread1);
    std::thread th2(thread2);

    th1.join();
    th2.join();

    return 0;
}<commit_msg>fix test for epoll<commit_after>#include "lunar_green_thread.hpp"

#include <iostream>

volatile int n = 0;

void
func3(void *arg) {
    auto ws = (lunar::shared_stream*)arg;
    for (;;) {
        lunar::select_green_thread(nullptr, 0, nullptr, 0, false, 11000);
        auto ret = lunar::push_ptr(ws, nullptr);
        assert(ret == lunar::STRM_SUCCESS);
        fflush(stdout);
    }
}

void
func1(void *arg)
{
    n++;
    while(n != 2); // barrier

    auto rs = new lunar::shared_stream;
    auto ws = new lunar::shared_stream;
    lunar::make_ptr_stream(rs, ws, 1);

    lunar::spawn_green_thread(func3, ws);

#ifdef KQUEUE
    struct kevent kev;
    EV_SET(&kev, STDIN_FILENO, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
#elif (defined EPOLL)
    epoll_event eev;
    eev.data.fd = STDIN_FILENO;
    eev.events  = EPOLLIN;
#endif // KQUEUE

    printf("> ");
    fflush(stdout);

    for (;;) {
#ifdef KQUEUE
        lunar::select_green_thread(&kev, 1, (void**)&rs, 1, true, 5000);
#elif (defined EPOLL)
        lunar::select_green_thread(&eev, 1, (void**)&rs, 1, true, 5000);
#endif // KQUEUE

        if (lunar::is_timeout_green_thread()) {
            printf("timeout!\n> ");
            fflush(stdout);
        }

        if (lunar::is_ready_threadq_green_thread()) {
            void *data;
            auto ret = lunar::pop_threadq_green_thread(&data);
            assert(ret == lunar::STRM_SUCCESS);

            printf("recv thread queue!\n> ");
            fflush(stdout);
        }

        void **streams;
        ssize_t len;
        lunar::get_streams_ready_green_thread(&streams, &len);
        for (int i = 0; i < len; i++) {
            void *val;
            auto ret = lunar::pop_ptr((lunar::shared_stream*)streams[i], &val);
            assert(ret == lunar::STRM_SUCCESS);
            printf("recv stream!\n> ");
            fflush(stdout);
        }

        lunar::fdevent_green_thread *fdev;
        lunar::get_fds_ready_green_thread(&fdev, &len);
        for (int i = 0; i < len; i++) {
            if (fdev[i].fd == STDIN_FILENO && fdev[i].event == FD_EV_READ) {
                std::string s;
                std::cin >> s;
                printf("input = %s\n> ", s.c_str());
                fflush(stdout);
            }
        }
    }
}

void
func2(void *arg)
{
    n++;
    while(n != 2); // barrier

    auto fb = lunar::get_green_thread(1);
    for (;;) {
        lunar::select_green_thread(nullptr, 0, nullptr, 0, false, 13000);
        lunar::push_threadq_fast_unsafe_green_thread(fb, nullptr);
    }
}

void
thread2()
{
    lunar::init_green_thread(2);
    lunar::spawn_green_thread(func2);
    lunar::run_green_thread();
}

void
thread1()
{
    lunar::init_green_thread(1);
    lunar::spawn_green_thread(func1);
    lunar::run_green_thread();
}

int
main(int argc, char *argv[])
{
    std::thread th1(thread1);
    std::thread th2(thread2);

    th1.join();
    th2.join();

    return 0;
}<|endoftext|>


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

#ifndef SPIN_MUTEX_HPP
#define SPIN_MUTEX_HPP

class spin_mutex {
   bool _locked;

public:
   spin_mutex() {
      __atomic_clear( &_locked, __ATOMIC_RELAXED );
   }

   void lock() {
      while( !try_lock() )
         __asm__("pause" :: "memory");
   }

   void unlock() {
      __atomic_clear( &_locked, __ATOMIC_RELEASE );
   }

   bool try_lock() {
      return !__atomic_test_and_set( &_locked, __ATOMIC_ACQUIRE );
   }
};

#endif // SPIN_MUTEX_HPP

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

#ifndef SPIN_MUTEX_HPP
#define SPIN_MUTEX_HPP

class spin_mutex {
   bool _locked;

public:
   spin_mutex() {
      __atomic_clear( &_locked, __ATOMIC_RELAXED );
   }

   void lock() {
      while( !try_lock() )
         __asm__("pause" ::: "memory");
   }

   void unlock() {
      __atomic_clear( &_locked, __ATOMIC_RELEASE );
   }

   bool try_lock() {
      return !__atomic_test_and_set( &_locked, __ATOMIC_ACQUIRE );
   }
};

#endif // SPIN_MUTEX_HPP

<|endoftext|>


<commit_before>#include "parser.hpp"

static void gen_msg_glb(const std::size_t lvl)
{
	s_outf_converter.pf(lvl, "/// mid to string\n");
	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_mid_to_str[] = {\n");
	s_outf_converter.pf(lvl+1, "\"nil\",\n");
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		s_outf_converter.pf(lvl+1, "\"%s\",\n", evt_name);
	}
	s_outf_converter.pf(lvl, "};\n\n");

	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_id = \"msgid\";\n");
	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_data = \"data\";\n");
}

static void generate_msg_sender_header(std::size_t lvl)
{
	s_outf_sender.pf(lvl, R"senderheader(
/// @class sender : used to send messages
class sender final {
public:
	sender(size_t reserve_header_size = 0);
	~sender();
public:
	template<mid_t mid, typename _T >
	void fill_to(typename msg_helper<mid>::value_type const & msg,  _T & o, void (_T::*f)(void *, size_t))
	{
		__reset(mid);
		__pack(msg);
		__serialize();
		o.f(m_buf, __size());
	}

	template< mid_t mid >
	void fill_to(typename msg_helper<mid>::value_type const & msg, std::function<void(void *, size_t)>  f)
	{
		__reset(mid);
		__pack(msg);
		__serialize();
		f(m_buf, __size());
	}
)senderheader");

	for (const auto & itr: s_export_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_sender.pf(lvl+1, "void convert(std::string & dst, const struct %s & src);\n", type_name);
	}

	s_outf_sender.pf(lvl, R"senderheader(
private:
)senderheader");

	for (const auto & itr: s_msg_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_sender.pf(lvl+1, "void __pack(const struct %s & val);\n", type_name);
	}

	s_outf_sender.pf(lvl, R"senderheader(
private:
	void __reset(mid_t mid);
	void __serialize();
private:
	std::size_t __size() const
	{
		return (m_pcur - m_buf);
	}
private:
	void __fill_header();
private:
	uint8_t m_lbuf[65536];
	uint8_t * const m_buf;
	uint8_t * m_pcur;
	const uint8_t * const m_pend;
	void * m_doc;
};

)senderheader");

	s_outf_sender.pf(lvl, "\n");
}

static void generate_msg_sender_implement(std::size_t lvl)
{
	s_outf_converter.pf(lvl, R"senderfillheader(
/// @sender constructor
sender::sender(size_t reserve_header_size)
: m_buf(&m_lbuf[reserve_header_size + LWS_PRE])
, m_pcur(m_buf)
, m_pend(m_lbuf + sizeof(m_lbuf))
, m_doc(new rapidjson::Document())
{}

/// @sender destructor
sender::~sender()
{
	delete (rapidjson::Document*)m_doc;
}

/// @sender reset
void sender::__reset(mid_t mid)
{
	m_pcur = m_buf;
	((rapidjson::Document*)m_doc)->SetObject();

	rapidjson::Document & doc = *(rapidjson::Document *)m_doc;
	doc.AddMember(s_id, s_mid_to_str[(%s)mid], doc.GetAllocator());
}

/// @sender serialize
void sender::__serialize()
{
	out_wrapper buf((char *)m_pcur);
	rapidjson::Writer<out_wrapper> writer(buf);
	((rapidjson::Document *)m_doc)->Accept(writer);
	m_pcur = (uint8_t *)buf.pcur;
}

)senderfillheader", s_mid_under_type);
	s_outf_converter.pf(lvl, "\n");

	for (const auto & itr: s_export_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void sender::convert(std::string & dst, const struct %s & src)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *(rapidjson::Document*)m_doc;\n");
		s_outf_converter.pf(lvl+1, "out_string_wrapper buf(dst);\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Writer<out_string_wrapper> writer(buf);\n");
		s_outf_converter.pf(lvl+1, "c2json(doc, src).Accept(writer);\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}

	s_outf_converter.pf(lvl, "/// messages packer wrapper\n");
	for (const auto & itr: s_msg_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void sender::__pack(const struct %s & val)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *(rapidjson::Document *)m_doc;\n");
		s_outf_converter.pf(lvl+1, "doc.AddMember(s_data, c2json(doc, val), doc.GetAllocator());\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
}

static void generate_msg_rcver_header(std::size_t lvl)
{
	s_outf_rcver.pf(lvl, R"rcverheader(
/// @class rcver : used to receive messages
class rcver final {
public:
	rcver();
	~rcver();
public:
	void process(void *, size_t);

	template<mid_t mid, template<mid_t> class T>
	void register_callback(std::function<void(T<mid> &)> cb)
	{
		m_cbs[__mid_to_str(mid)] = [this, cb](void) -> void {
			T<mid> tmp;
			__unpack((typename msg_helper<mid>::value_type &)tmp);
			cb(tmp);
		};
	}

	template<mid_t mid>
	void register_callback(std::function<void(typename msg_helper<mid>::value_type &)> cb)
	{
		m_cbs[__mid_to_str(mid)] = [this, cb](void) -> void {
			typename msg_helper<mid>::value_type msg;
			__unpack(msg);
			cb(msg);
		};
	}
)rcverheader");

	for (const auto & itr: s_export_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl+1, "void convert(struct %s & dst, const std::string & src);\n", type_name);
	}

	s_outf_rcver.pf(lvl, R"rcverheader(
private:
	const char * __mid_to_str(mid_t mid);
)rcverheader");

	for (const auto & itr: s_msg_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl+1, "void __unpack(struct %s & dst);\n", type_name);
	}

	s_outf_rcver.pf(lvl, R"rcverheader(
private:
	void __reset();
private:
	void * m_doc;
	std::map<std::string, std::function<void(void)>> m_cbs;
};

)rcverheader");
#if 0
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		const rapidjson::Value & val = *(itr.second);
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl, "template<> void rcver::register_callback<mid_t::%s>(std::function< void(std::function<void(struct %s&)>)> f);\n", evt_name, type_name);
	}
#endif

	s_outf_rcver.pf(lvl, "\n");
}

static void generate_msg_rcver_implement(std::size_t lvl)
{
	s_outf_converter.pf(lvl, R"rcverimplementer(
/// @class rcver : used to receive messages
rcver::rcver()
: m_doc(new rapidjson::Document())
{}

rcver::~rcver()
{
	delete (rapidjson::Document*)m_doc;
}

void rcver::__reset()
{
	((rapidjson::Document*)m_doc)->SetNull();
}

void rcver::process(void * buf, size_t /*len*/)
{
	/// process
	rapidjson::Document & doc = *((rapidjson::Document*)m_doc);
	doc.ParseInsitu((char *)buf);
	auto & cb = m_cbs[doc.FindMember(s_id)->value.GetString()];
	if (cb) { cb(); }

	__reset();
}

)rcverimplementer");

	for (const auto & itr: s_export_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void rcver::convert(struct %s & dst, const std::string & src)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *((rapidjson::Document*)m_doc);\n");
		s_outf_converter.pf(lvl+1, "doc.Parse(src);\n");
		s_outf_converter.pf(lvl+1, "json2c(dst, doc);\n");
		s_outf_converter.pf(lvl+1, "__reset();\n");
		s_outf_converter.pf(lvl, "}\n\n", type_name);
	}

#if 0
	/// register callback
	s_outf_converter.pf(lvl, "/// messages register\n");
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		const rapidjson::Value & val = *(itr.second);
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "template<>\n");
		s_outf_converter.pf(lvl, "void rcver::register_callback<mid_t::%s>(std::function< void(std::function<void(struct %s&)>)> f)\n", evt_name, type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "auto getter = [this](struct %s & dst) -> void {\n", type_name);
		s_outf_converter.pf(lvl+2, "json2c(dst, ((rapidjson::Document*)m_doc)->FindMember(\"data\")->value);\n");
		s_outf_converter.pf(lvl+1, "};\n");
		s_outf_converter.pf(lvl+1, "m_cbs[\"%s\"] = [getter, f]()->void {\n", evt_name);
		s_outf_converter.pf(lvl+2, "f(getter);\n");
		s_outf_converter.pf(lvl+1, "};\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
#endif
	/// mid to string
	s_outf_converter.pf(lvl, "/// mid to string\n");
	s_outf_converter.pf(lvl, "const char * rcver::__mid_to_str(mid_t mid)\n");
	s_outf_converter.pf(lvl, "{\n");
	s_outf_converter.pf(lvl+1, "return s_mid_to_str[(%s)mid];\n", s_mid_under_type);
	s_outf_converter.pf(lvl, "}\n\n");

	/// unpack
	s_outf_converter.pf(lvl, "/// messages unpack\n");
	for (const auto & itr: s_msg_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void rcver::__unpack(struct %s & dst)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "json2c(dst, ((rapidjson::Document*)m_doc)->FindMember(s_data)->value);\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
}

void generate_wsmsgs(rapidjson::Document & /*d*/)
{
	const std::size_t lvl = 0;

	gen_msg_glb(lvl);

	generate_msg_sender_header(lvl);
	generate_msg_sender_implement(lvl);

	generate_msg_rcver_header(lvl);
	generate_msg_rcver_implement(lvl);
}
<commit_msg>idl: add c string support for rcver::convert<commit_after>#include "parser.hpp"

static void gen_msg_glb(const std::size_t lvl)
{
	s_outf_converter.pf(lvl, "/// mid to string\n");
	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_mid_to_str[] = {\n");
	s_outf_converter.pf(lvl+1, "\"nil\",\n");
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		s_outf_converter.pf(lvl+1, "\"%s\",\n", evt_name);
	}
	s_outf_converter.pf(lvl, "};\n\n");

	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_id = \"msgid\";\n");
	s_outf_converter.pf(lvl, "static rapidjson::Value::StringRefType const s_data = \"data\";\n");
}

static void generate_msg_sender_header(std::size_t lvl)
{
	s_outf_sender.pf(lvl, R"senderheader(
/// @class sender : used to send messages
class sender final {
public:
	sender(size_t reserve_header_size = 0);
	~sender();
public:
	template<mid_t mid, typename _T >
	void fill_to(typename msg_helper<mid>::value_type const & msg,  _T & o, void (_T::*f)(void *, size_t))
	{
		__reset(mid);
		__pack(msg);
		__serialize();
		o.f(m_buf, __size());
	}

	template< mid_t mid >
	void fill_to(typename msg_helper<mid>::value_type const & msg, std::function<void(void *, size_t)>  f)
	{
		__reset(mid);
		__pack(msg);
		__serialize();
		f(m_buf, __size());
	}
)senderheader");

	for (const auto & itr: s_export_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_sender.pf(lvl+1, "void convert(std::string & dst, const struct %s & src);\n", type_name);
	}

	s_outf_sender.pf(lvl, R"senderheader(
private:
)senderheader");

	for (const auto & itr: s_msg_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_sender.pf(lvl+1, "void __pack(const struct %s & val);\n", type_name);
	}

	s_outf_sender.pf(lvl, R"senderheader(
private:
	void __reset(mid_t mid);
	void __serialize();
private:
	std::size_t __size() const
	{
		return (m_pcur - m_buf);
	}
private:
	void __fill_header();
private:
	uint8_t m_lbuf[65536];
	uint8_t * const m_buf;
	uint8_t * m_pcur;
	const uint8_t * const m_pend;
	void * m_doc;
};

)senderheader");

	s_outf_sender.pf(lvl, "\n");
}

static void generate_msg_sender_implement(std::size_t lvl)
{
	s_outf_converter.pf(lvl, R"senderfillheader(
/// @sender constructor
sender::sender(size_t reserve_header_size)
: m_buf(&m_lbuf[reserve_header_size + LWS_PRE])
, m_pcur(m_buf)
, m_pend(m_lbuf + sizeof(m_lbuf))
, m_doc(new rapidjson::Document())
{}

/// @sender destructor
sender::~sender()
{
	delete (rapidjson::Document*)m_doc;
}

/// @sender reset
void sender::__reset(mid_t mid)
{
	m_pcur = m_buf;
	((rapidjson::Document*)m_doc)->SetObject();

	rapidjson::Document & doc = *(rapidjson::Document *)m_doc;
	doc.AddMember(s_id, s_mid_to_str[(%s)mid], doc.GetAllocator());
}

/// @sender serialize
void sender::__serialize()
{
	out_wrapper buf((char *)m_pcur);
	rapidjson::Writer<out_wrapper> writer(buf);
	((rapidjson::Document *)m_doc)->Accept(writer);
	m_pcur = (uint8_t *)buf.pcur;
}

)senderfillheader", s_mid_under_type);
	s_outf_converter.pf(lvl, "\n");

	for (const auto & itr: s_export_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void sender::convert(std::string & dst, const struct %s & src)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *(rapidjson::Document*)m_doc;\n");
		s_outf_converter.pf(lvl+1, "out_string_wrapper buf(dst);\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Writer<out_string_wrapper> writer(buf);\n");
		s_outf_converter.pf(lvl+1, "c2json(doc, src).Accept(writer);\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}

	s_outf_converter.pf(lvl, "/// messages packer wrapper\n");
	for (const auto & itr: s_msg_order) {
		/// @todo maybe not struct
		const rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void sender::__pack(const struct %s & val)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *(rapidjson::Document *)m_doc;\n");
		s_outf_converter.pf(lvl+1, "doc.AddMember(s_data, c2json(doc, val), doc.GetAllocator());\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
}

static void generate_msg_rcver_header(std::size_t lvl)
{
	s_outf_rcver.pf(lvl, R"rcverheader(
/// @class rcver : used to receive messages
class rcver final {
public:
	rcver();
	~rcver();
public:
	void process(void *, size_t);

	template<mid_t mid, template<mid_t> class T>
	void register_callback(std::function<void(T<mid> &)> cb)
	{
		m_cbs[__mid_to_str(mid)] = [this, cb](void) -> void {
			T<mid> tmp;
			__unpack((typename msg_helper<mid>::value_type &)tmp);
			cb(tmp);
		};
	}

	template<mid_t mid>
	void register_callback(std::function<void(typename msg_helper<mid>::value_type &)> cb)
	{
		m_cbs[__mid_to_str(mid)] = [this, cb](void) -> void {
			typename msg_helper<mid>::value_type msg;
			__unpack(msg);
			cb(msg);
		};
	}

	template<typename _T>
	void convert(_T & dst, const std::string & src)
	{
		convert(dst, src.c_str());
	}
)rcverheader");

	for (const auto & itr: s_export_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl+1, "void convert(struct %s & dst, const char * src);\n", type_name);
	}

	s_outf_rcver.pf(lvl, R"rcverheader(
private:
	const char * __mid_to_str(mid_t mid);
)rcverheader");

	for (const auto & itr: s_msg_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl+1, "void __unpack(struct %s & dst);\n", type_name);
	}

	s_outf_rcver.pf(lvl, R"rcverheader(
private:
	void __reset();
private:
	void * m_doc;
	std::map<std::string, std::function<void(void)>> m_cbs;
};

)rcverheader");
#if 0
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		const rapidjson::Value & val = *(itr.second);
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_rcver.pf(lvl, "template<> void rcver::register_callback<mid_t::%s>(std::function< void(std::function<void(struct %s&)>)> f);\n", evt_name, type_name);
	}
#endif

	s_outf_rcver.pf(lvl, "\n");
}

static void generate_msg_rcver_implement(std::size_t lvl)
{
	s_outf_converter.pf(lvl, R"rcverimplementer(
/// @class rcver : used to receive messages
rcver::rcver()
: m_doc(new rapidjson::Document())
{}

rcver::~rcver()
{
	delete (rapidjson::Document*)m_doc;
}

void rcver::__reset()
{
	((rapidjson::Document*)m_doc)->SetNull();
}

void rcver::process(void * buf, size_t /*len*/)
{
	/// process
	rapidjson::Document & doc = *((rapidjson::Document*)m_doc);
	doc.ParseInsitu((char *)buf);
	auto & cb = m_cbs[doc.FindMember(s_id)->value.GetString()];
	if (cb) { cb(); }

	__reset();
}

)rcverimplementer");

	for (const auto & itr: s_export_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void rcver::convert(struct %s & dst, const char * src)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "rapidjson::Document & doc = *((rapidjson::Document*)m_doc);\n");
		s_outf_converter.pf(lvl+1, "doc.Parse(src);\n");
		s_outf_converter.pf(lvl+1, "json2c(dst, doc);\n");
		s_outf_converter.pf(lvl+1, "__reset();\n");
		s_outf_converter.pf(lvl, "}\n\n", type_name);
	}

#if 0
	/// register callback
	s_outf_converter.pf(lvl, "/// messages register\n");
	for (const auto & itr: s_msg_lists) {
		const char * evt_name = itr.first.c_str();
		const rapidjson::Value & val = *(itr.second);
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "template<>\n");
		s_outf_converter.pf(lvl, "void rcver::register_callback<mid_t::%s>(std::function< void(std::function<void(struct %s&)>)> f)\n", evt_name, type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "auto getter = [this](struct %s & dst) -> void {\n", type_name);
		s_outf_converter.pf(lvl+2, "json2c(dst, ((rapidjson::Document*)m_doc)->FindMember(\"data\")->value);\n");
		s_outf_converter.pf(lvl+1, "};\n");
		s_outf_converter.pf(lvl+1, "m_cbs[\"%s\"] = [getter, f]()->void {\n", evt_name);
		s_outf_converter.pf(lvl+2, "f(getter);\n");
		s_outf_converter.pf(lvl+1, "};\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
#endif
	/// mid to string
	s_outf_converter.pf(lvl, "/// mid to string\n");
	s_outf_converter.pf(lvl, "const char * rcver::__mid_to_str(mid_t mid)\n");
	s_outf_converter.pf(lvl, "{\n");
	s_outf_converter.pf(lvl+1, "return s_mid_to_str[(%s)mid];\n", s_mid_under_type);
	s_outf_converter.pf(lvl, "}\n\n");

	/// unpack
	s_outf_converter.pf(lvl, "/// messages unpack\n");
	for (const auto & itr: s_msg_order) {
		rapidjson::Value & val = *itr;
		const char * type_name = val.FindMember("name")->value.GetString();
		s_outf_converter.pf(lvl, "void rcver::__unpack(struct %s & dst)\n", type_name);
		s_outf_converter.pf(lvl, "{\n");
		s_outf_converter.pf(lvl+1, "json2c(dst, ((rapidjson::Document*)m_doc)->FindMember(s_data)->value);\n");
		s_outf_converter.pf(lvl, "}\n\n");
	}
}

void generate_wsmsgs(rapidjson::Document & /*d*/)
{
	const std::size_t lvl = 0;

	gen_msg_glb(lvl);

	generate_msg_sender_header(lvl);
	generate_msg_sender_implement(lvl);

	generate_msg_rcver_header(lvl);
	generate_msg_rcver_implement(lvl);
}
<|endoftext|>


<commit_before>
#include <Hord/utility.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/PropStateStore.hpp>

#include <cassert>
#include <iostream>
#include <bitset>

using Hord::enum_cast;
using Type = Hord::IO::PropType;
using State = Hord::IO::PropState;
using Store = Hord::IO::PropStateStore;

void
print_store(
	Store const& s,
	Type const t = static_cast<Type>(0u)
) {
	bool const typed = 0u != enum_cast(t);
	unsigned const value
		= typed
		? enum_cast(s.get_state(t))
		: s.get_value()
	;

	if (typed) {
		std::cout
			<< Hord::IO::get_prop_type_name(t) << ": "
			<< std::bitset<4u>{value}
		;
	} else {
		std::cout
			<< "value: "
			<< std::bitset<4u>{value >> (4 << 2)} << ' '
			<< std::bitset<4u>{value >> (3 << 2)} << ' '
			<< std::bitset<4u>{value >> (2 << 2)} << ' '
			<< std::bitset<4u>{value >> (1 << 2)} << ' '
			<< std::bitset<4u>{value >> (0 << 2)} << ' '
		;
	}
	std::cout << '\n';
}

signed
main() {
	Store
		s_all{true, true},
		s_neither{false, false}
	;
	unsigned const
		value_init_all = s_all.get_value(),
		value_init_neither = s_neither.get_value()
	;

	std::cout << "s_all:\n";
	print_store(s_all);
	print_store(s_all, Type::primary);
	print_store(s_all, Type::auxiliary);

	std::cout << "\ns_neither:\n";
	print_store(s_neither);
	print_store(s_neither, Type::primary);
	print_store(s_neither, Type::auxiliary);

	std::cout << '\n';

	// Constructed state
	assert(s_all.all_uninitialized());
	assert(s_neither.all_uninitialized());

	assert(0u == value_init_all);

	assert(!s_all.all_original());
	assert(!s_all.any_modified());

	assert(!s_all.has(Type::primary, State::original));
	assert(!s_all.has(Type::auxiliary, State::original));

	assert(s_neither.has(Type::primary, State::original));
	assert(s_neither.has(Type::auxiliary, State::original));

	assert(s_all.is_supplied(Type::primary));
	assert(s_all.is_supplied(Type::auxiliary));

	assert(!s_neither.is_supplied(Type::primary));
	assert(!s_neither.is_supplied(Type::auxiliary));

	// Unchanged when resetting while all_uninitialized()
	s_all.reset_all();
	assert(s_all.get_value() == value_init_all);

	s_neither.reset_all();
	assert(s_neither.get_value() == value_init_neither);

	// Unsupplied props are unassignable
	s_neither.reset(Type::primary);
	s_neither.assign(Type::auxiliary, State::modified);
	assert(s_neither.get_value() == value_init_neither);

	// Assignments
	s_all.assign(Type::identity, State::original);
	s_all.assign(Type::metadata, State::original);
	s_all.assign(Type::scratch, State::original);
	s_all.assign(Type::primary, State::original);
	s_all.assign(Type::auxiliary, State::original);

	print_store(s_all);

	assert(s_all.all_original());
	assert(!s_all.any_modified());

	// Back to initial value when resetting
	s_all.reset_all();
	assert(s_all.get_value() == value_init_all);

	// More assignments
	s_all.assign(Type::identity, State::modified);
	s_all.assign(Type::metadata, State::modified);
	s_all.assign(Type::scratch, State::modified);
	s_all.assign(Type::primary, State::modified);
	s_all.assign(Type::auxiliary, State::modified);

	print_store(s_all);

	assert(!s_all.all_original());
	assert(s_all.any_modified());

	return 0;
}
<commit_msg>io/prop_state_store: added assign_all() test; tidy.<commit_after>
#include <Hord/utility.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/PropStateStore.hpp>

#include <cassert>
#include <iostream>
#include <bitset>

using Hord::enum_cast;
using Type = Hord::IO::PropType;
using State = Hord::IO::PropState;
using Store = Hord::IO::PropStateStore;

void
print_store(
	Store const& s,
	Type const t = static_cast<Type>(0u)
) {
	bool const typed = 0u != enum_cast(t);
	unsigned const value
		= typed
		? enum_cast(s.get_state(t))
		: s.get_value()
	;

	if (typed) {
		std::cout
			<< Hord::IO::get_prop_type_name(t) << ": "
			<< std::bitset<4u>{value}
		;
	} else {
		std::cout
			<< "value: "
			<< std::bitset<4u>{value >> (4 << 2)} << ' '
			<< std::bitset<4u>{value >> (3 << 2)} << ' '
			<< std::bitset<4u>{value >> (2 << 2)} << ' '
			<< std::bitset<4u>{value >> (1 << 2)} << ' '
			<< std::bitset<4u>{value >> (0 << 2)} << ' '
		;
	}
	std::cout << '\n';
}

void
assignments(
	Store& s,
	unsigned const initial
) {
	s.assign(Type::identity, State::modified);
	s.assign(Type::metadata, State::modified);
	s.assign(Type::scratch, State::modified);
	s.assign(Type::primary, State::modified);
	s.assign(Type::auxiliary, State::modified);
	print_store(s);

	assert(!s.all_original());
	assert(s.any_modified());

	s.assign(Type::identity, State::original);
	s.assign(Type::metadata, State::original);
	s.assign(Type::scratch, State::original);
	s.assign(Type::primary, State::original);
	s.assign(Type::auxiliary, State::original);
	print_store(s);

	assert(s.all_original());
	assert(!s.any_modified());

	// Back to initial value when resetting
	s.reset_all();
	assert(s.get_value() == initial);

	s.assign_all(State::original);
	print_store(s);

	assert(s.all_original());
	assert(!s.any_modified());
}

signed
main() {
	Store
		s_all{true, true},
		s_neither{false, false}
	;
	unsigned const
		value_init_all = s_all.get_value(),
		value_init_neither = s_neither.get_value()
	;

	// Constructed state
	assert(s_all.all_uninitialized());
	assert(s_neither.all_uninitialized());

	assert(0u == value_init_all);

	// Unchanged when resetting while all_uninitialized()
	s_all.reset_all();
	assert(s_all.get_value() == value_init_all);

	s_neither.reset_all();
	assert(s_neither.get_value() == value_init_neither);

	// Unsupplied props are unassignable
	s_neither.reset(Type::primary);
	s_neither.assign(Type::auxiliary, State::modified);
	assert(s_neither.get_value() == value_init_neither);

	// Traits
	std::cout << "s_all:\n";
	print_store(s_all);
	print_store(s_all, Type::primary);
	print_store(s_all, Type::auxiliary);

	assert(s_all.is_supplied(Type::primary));
	assert(s_all.is_supplied(Type::auxiliary));
	assert(!s_all.all_original());
	assert(!s_all.any_modified());
	assert(!s_all.has(Type::primary, State::modified));
	assert(!s_all.has(Type::auxiliary, State::modified));
	assert(!s_all.has(Type::primary, State::original));
	assert(!s_all.has(Type::auxiliary, State::original));

	assignments(s_all, value_init_all);

	std::cout << "\ns_neither:\n";
	print_store(s_neither);
	print_store(s_neither, Type::primary);
	print_store(s_neither, Type::auxiliary);

	assert(!s_neither.is_supplied(Type::primary));
	assert(!s_neither.is_supplied(Type::auxiliary));
	assert(!s_neither.all_original());
	assert(!s_neither.any_modified());
	assert(!s_neither.has(Type::primary, State::modified));
	assert(!s_neither.has(Type::auxiliary, State::modified));
	assert(s_neither.has(Type::primary, State::original));
	assert(s_neither.has(Type::auxiliary, State::original));

	assignments(s_neither, value_init_neither);

	return 0;
}
<|endoftext|>


<commit_before>
#include <map>

#include "vtrc-connection-list.h"
#include "vtrc-mutex-typedefs.h"

namespace vtrc { namespace common {

    namespace {

        typedef common::connection_iface_sptr connection_sptr;
        typedef common::connection_iface_wptr connection_wptr;

        typedef std::map <
            common::connection_iface *, connection_sptr
        > client_map_type;
    }

    struct connection_list::impl {

        client_map_type      clients_;
        mutable shared_mutex clients_lock_;

        void clear( )
        {
            unique_shared_lock l(clients_lock_);
            clients_.clear( );
        }

        void store( common::connection_iface *c )
        {
            store( c->shared_from_this( ) );
        }

        void store( common::connection_iface_sptr c )
        {
            unique_shared_lock l(clients_lock_);
            clients_.insert(std::make_pair(c.get( ), c));
        }

        connection_sptr lock( common::connection_iface *c )
        {
            connection_sptr result;
            shared_lock l(clients_lock_);
            client_map_type::iterator f( clients_.find( c ) );
            if( f != clients_.end( ) )
                result = f->second;
            return result;
        }

        void drop ( common::connection_iface *c )
        {
            upgradable_lock lck(clients_lock_);
            client_map_type::iterator f(clients_.find(c));
            if( f != clients_.end( )) {
                upgrade_to_unique ulck(lck);
                clients_.erase( f );
            }
        }

        void drop ( common::connection_iface_sptr &c )
        {
            drop( c.get( ) );
        }

        size_t foreach_while(client_predic func)
        {
            shared_lock l(clients_lock_);
            size_t result = 0;

            client_map_type::iterator b(clients_.begin( ));
            const client_map_type::iterator e(clients_.end( ));

            for( ; b!=e; ++b ) {
                bool ot = func( b->second );
                result += ot;
                if( !ot ) break;
            }
            return result;
        }
    };

    connection_list::connection_list( )
        :impl_(new impl)
    { }

    vtrc::shared_ptr<connection_list> connection_list::create( )
    {
        vtrc::shared_ptr<connection_list> new_inst(new connection_list);

        return new_inst;
    }

    connection_list::~connection_list( )
    {
        delete impl_;
    }

    void connection_list::clear( )
    {
        impl_->clear( );
    }

    void connection_list::store( common::connection_iface *connection )
    {
        impl_->store( connection );
    }

    void connection_list::store(common::connection_iface_sptr connection)
    {
        impl_->store( connection );
    }

    void connection_list::drop ( common::connection_iface *connection )
    {
        impl_->drop( connection );
    }

    void connection_list::drop(common::connection_iface_sptr connection)
    {
        impl_->drop( connection );
    }

    size_t connection_list::foreach_while(client_predic func)
    {
        return impl_->foreach_while( func );
    }

}}
<commit_msg>proto; cmake file<commit_after>
#include <map>

#include "vtrc-connection-list.h"
#include "vtrc-mutex-typedefs.h"

namespace vtrc { namespace common {

    namespace {

        typedef common::connection_iface_sptr connection_sptr;
        typedef common::connection_iface_wptr connection_wptr;

        typedef std::map <
            common::connection_iface *, connection_sptr
        > client_map_type;
    }

    struct connection_list::impl {

        client_map_type      clients_;
        mutable shared_mutex clients_lock_;

        void clear( )
        {
            unique_shared_lock l(clients_lock_);
            clients_.clear( );
        }

        void store( common::connection_iface *c )
        {
            store( c->shared_from_this( ) );
        }

        void store( common::connection_iface_sptr c )
        {
            unique_shared_lock l(clients_lock_);
            // std::cout << "Store client: " << clients_.size( ) + 1 << "\n";
            clients_.insert(std::make_pair(c.get( ), c));
        }

        connection_sptr lock( common::connection_iface *c )
        {
            connection_sptr result;
            shared_lock l(clients_lock_);
            client_map_type::iterator f( clients_.find( c ) );
            if( f != clients_.end( ) )
                result = f->second;
            return result;
        }

        void drop ( common::connection_iface *c )
        {
            upgradable_lock lck(clients_lock_);
            client_map_type::iterator f(clients_.find(c));
            if( f != clients_.end( )) {
                upgrade_to_unique ulck(lck);
                // std::cout << "Drop client: " << clients_.size( ) - 1 << "\n";
                clients_.erase( f );
            }
        }

        void drop ( common::connection_iface_sptr &c )
        {
            drop( c.get( ) );
        }

        size_t foreach_while(client_predic func)
        {
            shared_lock l(clients_lock_);
            size_t result = 0;

            client_map_type::iterator b(clients_.begin( ));
            const client_map_type::iterator e(clients_.end( ));

            for( ; b!=e; ++b ) {
                bool ot = func( b->second );
                result += ot;
                if( !ot ) break;
            }
            return result;
        }
    };

    connection_list::connection_list( )
        :impl_(new impl)
    { }

    vtrc::shared_ptr<connection_list> connection_list::create( )
    {
        vtrc::shared_ptr<connection_list> new_inst(new connection_list);

        return new_inst;
    }

    connection_list::~connection_list( )
    {
        delete impl_;
    }

    void connection_list::clear( )
    {
        impl_->clear( );
    }

    void connection_list::store( common::connection_iface *connection )
    {
        impl_->store( connection );
    }

    void connection_list::store(common::connection_iface_sptr connection)
    {
        impl_->store( connection );
    }

    void connection_list::drop ( common::connection_iface *connection )
    {
        impl_->drop( connection );
    }

    void connection_list::drop(common::connection_iface_sptr connection)
    {
        impl_->drop( connection );
    }

    size_t connection_list::foreach_while(client_predic func)
    {
        return impl_->foreach_while( func );
    }

}}
<|endoftext|>