<commit_before>#include "log_ui.h"
#include "engine/log.h"
#include "engine/os.h"
#include "imgui/imgui.h"

namespace Lumix
{

LogUI::LogUI(IAllocator& allocator)
	: m_allocator(allocator)
	, m_messages(allocator)
	, m_level_filter(2 | 4)
	, m_notifications(allocator)
	, m_last_uid(1)
	, m_is_open(false)
	, m_are_notifications_hovered(false)
	, m_move_notifications_to_front(false)
{
	g_log_info.getCallback().bind<LogUI, &LogUI::onInfo>(this);
	g_log_error.getCallback().bind<LogUI, &LogUI::onError>(this);
	g_log_warning.getCallback().bind<LogUI, &LogUI::onWarning>(this);

	for (int i = 0; i < COUNT; ++i)
	{
		m_new_message_count[i] = 0;
	}
}

LogUI::~LogUI()
{
	g_log_info.getCallback().unbind<LogUI, &LogUI::onInfo>(this);
	g_log_error.getCallback().unbind<LogUI, &LogUI::onError>(this);
	g_log_warning.getCallback().unbind<LogUI, &LogUI::onWarning>(this);
}

void LogUI::setNotificationTime(int uid, float time)
{
	for (auto& notif : m_notifications)
	{
		if (notif.uid == uid)
		{
			notif.time = time;
			break;
		}
	}
}

int LogUI::addNotification(const char* text)
{
	m_move_notifications_to_front = true;
	if (!m_notifications.empty() && m_notifications.back().message == text) return -1;
	auto& notif = m_notifications.emplace(m_allocator);
	notif.time = 10.0f;
	notif.message = text;
	notif.uid = ++m_last_uid;
	return notif.uid;
}

void LogUI::push(Type type, const char* message)
{
	MT::SpinLock lock(m_guard);
	++m_new_message_count[type];
	Message& msg = m_messages.emplace(m_allocator);
	msg.text = message;
	msg.type = type;

	if (type == ERROR)
	{
		addNotification(message);
	}
}

void LogUI::onInfo(const char* system, const char* message)
{
	push(INFO, message);
}

void LogUI::onWarning(const char* system, const char* message)
{
	push(WARNING, message);
}

void LogUI::onError(const char* system, const char* message)
{
	push(ERROR, message);
}

void fillLabel(char* output, int max_size, const char* label, int count)
{
	copyString(output, max_size, label);
	catString(output, max_size, "(");
	int len = stringLength(output);
	toCString(count, output + len, max_size - len);
	catString(output, max_size, ")###");
	catString(output, max_size, label);
}

void LogUI::showNotifications()
{
	m_are_notifications_hovered = false;
	if (m_notifications.empty()) return;

	ImGui::SetNextWindowPos(ImVec2(10, 30));
	ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1);
	if (!ImGui::Begin("Notifications", nullptr, flags)) goto end;

	m_are_notifications_hovered = ImGui::IsWindowHovered();

	if (ImGui::Button("Close")) m_notifications.clear();

	if (m_move_notifications_to_front) ImGui::BringToFront();
	m_move_notifications_to_front = false;
	for (int i = 0; i < m_notifications.size(); ++i)
	{
		if (i > 0) ImGui::Separator();
		ImGui::Text("%s", m_notifications[i].message.c_str());
	}

	end:
		ImGui::End();
		ImGui::PopStyleVar();
}

void LogUI::update(float time_delta)
{
	if (m_are_notifications_hovered) return;

	for (int i = 0; i < m_notifications.size(); ++i)
	{
		m_notifications[i].time -= time_delta;

		if (m_notifications[i].time < 0)
		{
			m_notifications.erase(i);
			--i;
		}
	}
}

int LogUI::getUnreadErrorCount() const
{
	return m_new_message_count[ERROR];
}

void LogUI::onGUI()
{
	MT::SpinLock lock(m_guard);
	showNotifications();

	if (!m_is_open) return;
	if (ImGui::Begin("Log", &m_is_open))
	{
		const char* labels[] = { "Info", "Warning", "Error" };
		for (int i = 0; i < lengthOf(labels); ++i)
		{
			char label[40];
			fillLabel(label, sizeof(label), labels[i], m_new_message_count[i]);
			if(i > 0) ImGui::SameLine();
			bool b = m_level_filter & (1 << i);
			if (ImGui::Checkbox(label, &b))
			{
				if (b) m_level_filter |= 1 << i;
				else m_level_filter &= ~(1 << i);
				m_new_message_count[i] = 0;
			}
		}

		ImGui::SameLine();
		char filter[128] = "";
		ImGui::LabellessInputText("Filter", filter, sizeof(filter));
		int len = 0;

		if (ImGui::BeginChild("log_messages", ImVec2(0, 0), true))
		{
			for (int i = 0; i < m_messages.size(); ++i)
			{
				if ((m_level_filter & (1 << m_messages[i].type)) == 0) continue;
				const char* msg = m_messages[i].text.c_str();
				if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
				{
					ImGui::TextUnformatted(msg);
				}
			}
		}
		ImGui::EndChild();
		if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) ImGui::OpenPopup("Context");
		if (ImGui::BeginPopup("Context"))
		{
			if (ImGui::Selectable("Copy"))
			{
				for (int i = 0; i < m_messages.size(); ++i)
				{
					const char* msg = m_messages[i].text.c_str();
					if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
					{
						len += stringLength(msg);
					}
				}

				if (len > 0)
				{
					char* mem = (char*)m_allocator.allocate(len);
					mem[0] = '\0';
					for (int i = 0; i < m_messages.size(); ++i)
					{
						const char* msg = m_messages[i].text.c_str();
						if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
						{
							catString(mem, len, msg);
							catString(mem, len, "\n");
						}
					}

					OS::copyToClipboard(mem);
					m_allocator.deallocate(mem);
				}
			}
			if (ImGui::Selectable("Clear"))
			{
				Array<Message> filtered_messages(m_allocator);
				for (int i = 0; i < m_messages.size(); ++i)
				{
					if ((m_level_filter & (1 << m_messages[i].type)) != 0) continue;
					filtered_messages.emplace(m_messages[i]);
					m_new_message_count[m_messages[i].type] = 0;
				}
				m_messages.swap(filtered_messages);
			}
			ImGui::EndPopup();
		}
	}
	ImGui::End();
}

} // namespace Lumix
<commit_msg>limit size of notification window<commit_after>#include "log_ui.h"
#include "engine/log.h"
#include "engine/os.h"
#include "imgui/imgui.h"

namespace Lumix
{

LogUI::LogUI(IAllocator& allocator)
	: m_allocator(allocator)
	, m_messages(allocator)
	, m_level_filter(2 | 4)
	, m_notifications(allocator)
	, m_last_uid(1)
	, m_is_open(false)
	, m_are_notifications_hovered(false)
	, m_move_notifications_to_front(false)
{
	g_log_info.getCallback().bind<LogUI, &LogUI::onInfo>(this);
	g_log_error.getCallback().bind<LogUI, &LogUI::onError>(this);
	g_log_warning.getCallback().bind<LogUI, &LogUI::onWarning>(this);

	for (int i = 0; i < COUNT; ++i)
	{
		m_new_message_count[i] = 0;
	}
}

LogUI::~LogUI()
{
	g_log_info.getCallback().unbind<LogUI, &LogUI::onInfo>(this);
	g_log_error.getCallback().unbind<LogUI, &LogUI::onError>(this);
	g_log_warning.getCallback().unbind<LogUI, &LogUI::onWarning>(this);
}

void LogUI::setNotificationTime(int uid, float time)
{
	for (auto& notif : m_notifications)
	{
		if (notif.uid == uid)
		{
			notif.time = time;
			break;
		}
	}
}

int LogUI::addNotification(const char* text)
{
	m_move_notifications_to_front = true;
	if (!m_notifications.empty() && m_notifications.back().message == text) return -1;
	auto& notif = m_notifications.emplace(m_allocator);
	notif.time = 10.0f;
	notif.message = text;
	notif.uid = ++m_last_uid;
	return notif.uid;
}

void LogUI::push(Type type, const char* message)
{
	MT::SpinLock lock(m_guard);
	++m_new_message_count[type];
	Message& msg = m_messages.emplace(m_allocator);
	msg.text = message;
	msg.type = type;

	if (type == ERROR)
	{
		addNotification(message);
	}
}

void LogUI::onInfo(const char* system, const char* message)
{
	push(INFO, message);
}

void LogUI::onWarning(const char* system, const char* message)
{
	push(WARNING, message);
}

void LogUI::onError(const char* system, const char* message)
{
	push(ERROR, message);
}

void fillLabel(char* output, int max_size, const char* label, int count)
{
	copyString(output, max_size, label);
	catString(output, max_size, "(");
	int len = stringLength(output);
	toCString(count, output + len, max_size - len);
	catString(output, max_size, ")###");
	catString(output, max_size, label);
}

void LogUI::showNotifications()
{
	m_are_notifications_hovered = false;
	if (m_notifications.empty()) return;

	ImGui::SetNextWindowPos(ImVec2(10, 30));
	ImGui::SetNextWindowSizeConstraints(ImVec2(-FLT_MAX, 0), ImVec2(FLT_MAX, 200));
	ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
	ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1);
	if (!ImGui::Begin("Notifications", nullptr, flags)) goto end;

	m_are_notifications_hovered = ImGui::IsWindowHovered();

	if (ImGui::Button("Close")) m_notifications.clear();

	if (m_move_notifications_to_front) ImGui::BringToFront();
	m_move_notifications_to_front = false;
	for (int i = 0; i < m_notifications.size(); ++i)
	{
		if (i > 0) ImGui::Separator();
		ImGui::Text("%s", m_notifications[i].message.c_str());
	}

	end:
		ImGui::End();
		ImGui::PopStyleVar();
}

void LogUI::update(float time_delta)
{
	if (m_are_notifications_hovered) return;

	for (int i = 0; i < m_notifications.size(); ++i)
	{
		m_notifications[i].time -= time_delta;

		if (m_notifications[i].time < 0)
		{
			m_notifications.erase(i);
			--i;
		}
	}
}

int LogUI::getUnreadErrorCount() const
{
	return m_new_message_count[ERROR];
}

void LogUI::onGUI()
{
	MT::SpinLock lock(m_guard);
	showNotifications();

	if (!m_is_open) return;
	if (ImGui::Begin("Log", &m_is_open))
	{
		const char* labels[] = { "Info", "Warning", "Error" };
		for (int i = 0; i < lengthOf(labels); ++i)
		{
			char label[40];
			fillLabel(label, sizeof(label), labels[i], m_new_message_count[i]);
			if(i > 0) ImGui::SameLine();
			bool b = m_level_filter & (1 << i);
			if (ImGui::Checkbox(label, &b))
			{
				if (b) m_level_filter |= 1 << i;
				else m_level_filter &= ~(1 << i);
				m_new_message_count[i] = 0;
			}
		}

		ImGui::SameLine();
		char filter[128] = "";
		ImGui::LabellessInputText("Filter", filter, sizeof(filter));
		int len = 0;

		if (ImGui::BeginChild("log_messages", ImVec2(0, 0), true))
		{
			for (int i = 0; i < m_messages.size(); ++i)
			{
				if ((m_level_filter & (1 << m_messages[i].type)) == 0) continue;
				const char* msg = m_messages[i].text.c_str();
				if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
				{
					ImGui::TextUnformatted(msg);
				}
			}
		}
		ImGui::EndChild();
		if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) ImGui::OpenPopup("Context");
		if (ImGui::BeginPopup("Context"))
		{
			if (ImGui::Selectable("Copy"))
			{
				for (int i = 0; i < m_messages.size(); ++i)
				{
					const char* msg = m_messages[i].text.c_str();
					if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
					{
						len += stringLength(msg);
					}
				}

				if (len > 0)
				{
					char* mem = (char*)m_allocator.allocate(len);
					mem[0] = '\0';
					for (int i = 0; i < m_messages.size(); ++i)
					{
						const char* msg = m_messages[i].text.c_str();
						if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
						{
							catString(mem, len, msg);
							catString(mem, len, "\n");
						}
					}

					OS::copyToClipboard(mem);
					m_allocator.deallocate(mem);
				}
			}
			if (ImGui::Selectable("Clear"))
			{
				Array<Message> filtered_messages(m_allocator);
				for (int i = 0; i < m_messages.size(); ++i)
				{
					if ((m_level_filter & (1 << m_messages[i].type)) != 0) continue;
					filtered_messages.emplace(m_messages[i]);
					m_new_message_count[m_messages[i].type] = 0;
				}
				m_messages.swap(filtered_messages);
			}
			ImGui::EndPopup();
		}
	}
	ImGui::End();
}

} // namespace Lumix
<|endoftext|>


<commit_before>/***
Copyright 2012 Devsim LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

#include "Utility.hh"
#include "EquationObject.hh"

#include <algorithm>
#include <functional>

namespace Eqo {
namespace {
//// order by CONST_OBJ, the VARIABLE_OBJ, then everything else see enum
struct EqVecCompare : public std::binary_function<EqObjPtr, EqObjPtr, bool>
{
  bool operator()(EqObjPtr x, EqObjPtr y)
  {
    const EqObjType xtype = x->getType();
    const EqObjType ytype = y->getType();

    bool ret = false;

    if (xtype < ytype)
    {
      ret = true;
    }
    else if (xtype == ytype)
    {
      const std::string &xstr = x->stringValue();
      const std::string &ystr = y->stringValue();

      ret = (xstr < ystr);
    }

    return ret;
  }
};

}
/// Sorts in order of constants, variables, then other objects
void SortEqVector(std::vector<EqObjPtr> &v1)
{
  std::sort(v1.begin(), v1.end(), EqVecCompare());
}

}

<commit_msg>remove deprecated binary_function for c++17<commit_after>/***
Copyright 2012 Devsim LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

#include "Utility.hh"
#include "EquationObject.hh"

#include <algorithm>

namespace Eqo {
namespace {
//// order by CONST_OBJ, the VARIABLE_OBJ, then everything else see enum
struct EqVecCompare
{
  bool operator()(EqObjPtr x, EqObjPtr y)
  {
    const EqObjType xtype = x->getType();
    const EqObjType ytype = y->getType();

    bool ret = false;

    if (xtype < ytype)
    {
      ret = true;
    }
    else if (xtype == ytype)
    {
      const std::string &xstr = x->stringValue();
      const std::string &ystr = y->stringValue();

      ret = (xstr < ystr);
    }

    return ret;
  }
};

}
/// Sorts in order of constants, variables, then other objects
void SortEqVector(std::vector<EqObjPtr> &v1)
{
  std::sort(v1.begin(), v1.end(), EqVecCompare());
}

}

<|endoftext|>


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

#if MIOPEN_USE_MIOPENGEMM
namespace miopen {

// so that MIOpen works whether or not recent MIOpenGEMM changes pulled:
// convert size_t and ulong kernel function parameters to unsigned.
namespace tempfix {
void set_offsets_to_uint(std::string& clstr)
{

    for(char x : {'a', 'b', 'c'})
    {
        std::string replacement = "const unsigned " + std::string(1, x) + "_offset,";
        for(auto inttype : {"size_t", "ulong"})
        {
            std::string cmpstr =
                "const " + std::string(inttype) + ' ' + std::string(1, x) + "_offset,";
            auto pos = clstr.find(cmpstr);
            if(pos != std::string::npos)
            {
                clstr.replace(pos, cmpstr.size(), replacement);
                break;
            }
        }
    }
}
} // namespace tempfix

void GemmGeometry::EnableBetaKernel(bool enable) { beta_kern_req = enable; }

void GemmGeometry::FindSolution(
    float time, Handle& handle, ConstData_t a, ConstData_t b, Data_t c, bool enforce_determinism)
{

#if MIOPEN_BACKEND_OPENCL
    // jn : print search results to terminal
    bool miopengemm_verbose = false;

    // jn : print warning messages when the returned kernel(s) might be sub-optimal
    bool miopengemm_warnings = false;

    // jn : find with no workspace
    MIOpenGEMM::Solution soln = MIOpenGEMM::find(time,
                                                 handle.GetStream(),
                                                 a,
                                                 b,
                                                 c,
                                                 enforce_determinism,
                                                 tgg,
                                                 miopengemm_verbose,
                                                 miopengemm_warnings);
#else
    (void)time;
    (void)a;
    (void)b;
    (void)c;
    (void)enforce_determinism;
    (void)tgg;
    (void)alpha;
    (void)beta;
    MIOpenGEMM::Solution soln = MIOpenGEMM::get_default(tgg);
#endif

    // jn : the main kernel is at the back of the solution vector
    std::string kernel_clstring = soln.v_tgks.back().kernstr;
    tempfix::set_offsets_to_uint(kernel_clstring);

    std::string kernel_name    = soln.v_tgks.back().fname;
    std::string network_config = tgg.get_networkconfig_string();
    size_t local_work_size     = soln.v_tgks.back().local_work_size;
    size_t global_work_size    = soln.v_tgks.back().global_work_size;

    std::vector<size_t> vld{local_work_size, 1, 1};
    std::vector<size_t> vgd{global_work_size, 1, 1};

    handle.AddKernel(algorithm_name, network_config, kernel_clstring, kernel_name, vld, vgd, "");

    if(soln.v_tgks.size() == 2)
    {
        beta_kern_returned = true;
    }

    // jn : case where the beta kernel is part of the solution
    if(soln.v_tgks.size() == 2 && !miopen::float_equal(beta, 1))
    {
        std::string beta_program_name = soln.v_tgks[0].kernstr;
        tempfix::set_offsets_to_uint(beta_program_name);

        std::string beta_kernel_name = soln.v_tgks[0].fname;
        local_work_size              = soln.v_tgks[0].local_work_size;
        global_work_size             = soln.v_tgks[0].global_work_size;

        EnableBetaKernel(true);

        vld[0] = local_work_size;
        vgd[0] = global_work_size;

        handle.AddKernel(
            algorithm_name + "_beta",
            network_config, // jn : different network_configs require different beta kernels
            beta_program_name,
            beta_kernel_name,
            vld,
            vgd,
            "");
    }
    handle.geo_map[std::make_pair(algorithm_name, network_config)] =
        std::make_unique<GemmGeometry>(*this);
}

void GemmGeometry::RunGemm(Handle& handle,
                           ConstData_t a,
                           ConstData_t b,
                           Data_t c,
                           int a_offset,
                           int b_offset,
                           int c_offset)
{
    std::string network_config = tgg.get_networkconfig_string();

    if(beta_kern_req)
    {
        handle.GetKernel(algorithm_name + "_beta", network_config)(c, c_offset, beta);
        handle.GetKernel(algorithm_name,
                         network_config)(a, a_offset, b, b_offset, c, c_offset, alpha);
    }
    else
    {

        /* jn : the case where a beta kernel
         * was returned, but beta = 1 so it is not
         * needed. Notice: no beta in function sig  */
        if(beta_kern_returned)
        {
            handle.GetKernel(algorithm_name,
                             network_config)(a, a_offset, b, b_offset, c, c_offset, alpha);
        }
        else
        {
            handle.GetKernel(algorithm_name,
                             network_config)(a, a_offset, b, b_offset, c, c_offset, alpha, beta);
        }
    }
}

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

#if MIOPEN_USE_MIOPENGEMM
namespace miopen {

// so that MIOpen works whether or not recent MIOpenGEMM changes pulled:
// convert size_t and ulong kernel function parameters to unsigned.
namespace tempfix {
void set_offsets_to_uint(std::string& clstr)
{

    for(char x : {'a', 'b', 'c'})
    {
        std::string replacement = "const unsigned " + std::string(1, x) + "_offset,";
        for(auto inttype : {"size_t", "ulong"})
        {
            std::string cmpstr =
                "const " + std::string(inttype) + ' ' + std::string(1, x) + "_offset,";
            auto pos = clstr.find(cmpstr);
            if(pos != std::string::npos)
            {
                clstr.replace(pos, cmpstr.size(), replacement);
                break;
            }
        }
    }
}
} // namespace tempfix

void GemmGeometry::EnableBetaKernel(bool enable) { beta_kern_req = enable; }

void GemmGeometry::FindSolution(
    float time, Handle& handle, ConstData_t a, ConstData_t b, Data_t c, bool enforce_determinism)
{

#if MIOPEN_BACKEND_OPENCL
    // jn : print search results to terminal
    bool miopengemm_verbose = false;

    // jn : print warning messages when the returned kernel(s) might be sub-optimal
    bool miopengemm_warnings = false;

    // jn : find with no workspace
    MIOpenGEMM::Solution soln = MIOpenGEMM::find(time,
                                                 handle.GetStream(),
                                                 a,
                                                 b,
                                                 c,
                                                 enforce_determinism,
                                                 tgg,
                                                 miopengemm_verbose,
                                                 miopengemm_warnings);
#else
    (void)time;
    (void)a;
    (void)b;
    (void)c;
    (void)enforce_determinism;
    (void)tgg;
    (void)alpha;
    (void)beta;
    MIOpenGEMM::Solution soln = MIOpenGEMM::get_default(tgg);
#endif

    // jn : the main kernel is at the back of the solution vector
    std::string kernel_clstring = soln.v_tgks.back().kernstr;
    tempfix::set_offsets_to_uint(kernel_clstring);

    std::string kernel_name    = soln.v_tgks.back().fname;
    std::string network_config = tgg.get_networkconfig_string();
    size_t local_work_size     = soln.v_tgks.back().local_work_size;
    size_t global_work_size    = soln.v_tgks.back().global_work_size;

    std::vector<size_t> vld{local_work_size, 1, 1};
    std::vector<size_t> vgd{global_work_size, 1, 1};

    handle.AddKernel(algorithm_name, network_config, kernel_clstring, kernel_name, vld, vgd, "");

    if(soln.v_tgks.size() == 2)
    {
        beta_kern_returned = true;
    }

    // jn : case where the beta kernel is part of the solution
    if(soln.v_tgks.size() == 2 && !miopen::float_equal(beta, 1))
    {
        std::string beta_program_name = soln.v_tgks[0].kernstr;
        tempfix::set_offsets_to_uint(beta_program_name);

        std::string beta_kernel_name = soln.v_tgks[0].fname;
        local_work_size              = soln.v_tgks[0].local_work_size;
        global_work_size             = soln.v_tgks[0].global_work_size;

        EnableBetaKernel(true);

        vld[0] = local_work_size;
        vgd[0] = global_work_size;

        handle.AddKernel(
            algorithm_name + "_beta",
            network_config, // jn : different network_configs require different beta kernels
            beta_program_name,
            beta_kernel_name,
            vld,
            vgd,
            "");
    }
    handle.geo_map[std::make_pair(algorithm_name, network_config)] =
        std::make_unique<GemmGeometry>(*this);
}

void GemmGeometry::RunGemm(Handle& handle,
                           ConstData_t a,
                           ConstData_t b,
                           Data_t c,
                           int a_offset,
                           int b_offset,
                           int c_offset)
{
    std::string network_config = tgg.get_networkconfig_string();

    if(beta_kern_req)
    {
        handle.GetKernel(algorithm_name + "_beta", network_config)(c, c_offset, beta);
        handle.GetKernel(algorithm_name,
                         network_config)(a, a_offset, b, b_offset, c, c_offset, alpha);
    }
    else
    {

        /* jn : the case where a beta kernel
         * was returned, but beta = 1 so it is not
         * needed. Notice: no beta in function sig  */
        if(beta_kern_returned)
        {
            handle.GetKernel(algorithm_name,
                             network_config)(a, a_offset, b, b_offset, c, c_offset, alpha);
        }
        else
        {
            handle.GetKernel(algorithm_name,
                             network_config)(a, a_offset, b, b_offset, c, c_offset, alpha, beta);
        }
    }
}

} // namespace miopen
#endif // MIOPEN_USE_MIOPENGEMM
<|endoftext|>


<commit_before>#include "string.h"
#include <cstring>
#include <cmath>

namespace Lumix
{

static char makeLowercase(char c)
{
	return c >= 'A' && c <= 'Z' ? c - ('A' - 'a') : c;
}

int compareMemory(const void* lhs, const void* rhs, size_t size)
{
	return memcmp(lhs, rhs, size);
}

int compareStringN(const char* lhs, const char* rhs, int length)
{
	return strncmp(lhs, rhs, length);
}

int compareIStringN(const char* lhs, const char* rhs, int length)
{
#ifdef _WIN32
	return strnicmp(lhs, rhs, length);
#else
	return strncasecmp(lhs, rhs, length);
#endif
}

int compareString(const char* lhs, const char* rhs)
{
	return strcmp(lhs, rhs);
}

bool equalStrings(const char* lhs, const char* rhs)
{
	return strcmp(lhs, rhs) == 0;
}

int stringLength(const char* str)
{
	return (int)strlen(str);
}

void moveMemory(void* dest, const void* src, size_t count)
{
	memmove(dest, src, count);
}

void setMemory(void* ptr, uint8 value, size_t num)
{
	memset(ptr, value, num);
}

void copyMemory(void* dest, const void* src, size_t count)
{
	memcpy(dest, src, count);
}

bool endsWith(const char* str, const char* substr)
{
	int len = stringLength(str);
	int len2 = stringLength(substr);
	if (len2 > len) return false;
	return equalStrings(str + len - len2, substr);
}

const char* stristr(const char* haystack, const char* needle)
{
	const char* c = haystack;
	while (*c)
	{
		if (makeLowercase(*c) == makeLowercase(needle[0]))
		{
			const char* n = needle + 1;
			const char* c2 = c + 1;
			while (*n && *c2)
			{
				if (makeLowercase(*n) != makeLowercase(*c2)) break;
				++n;
				++c2;
			}
			if (*n == 0) return c;
		}
		++c;
	}
	return nullptr;
}

bool makeLowercase(char* destination, int length, const char* source)
{
	if (!source)
	{
		return false;
	}

	while (*source && length)
	{
		*destination = makeLowercase(*source);
		--length;
		++destination;
		++source;
	}
	if (length > 0)
	{
		*destination = 0;
		return true;
	}
	return false;
}

const char* findSubstring(const char* haystack, const char* needle)
{
	return strstr(haystack, needle);
}

bool copyNString(char* destination, int length, const char* source, int source_len)
{
	if (!source)
	{
		return false;
	}

	while (*source && length > 1 && source_len)
	{
		*destination = *source;
		--source_len;
		--length;
		++destination;
		++source;
	}
	if (length > 0)
	{
		*destination = 0;
		return *source == '\0' || source_len == 0;
	}
	return false;
}

bool copyString(char* destination, int length, const char* source)
{
	if (!source || length < 1)
	{
		return false;
	}

	while (*source && length > 1)
	{
		*destination = *source;
		--length;
		++destination;
		++source;
	}
	*destination = 0;
	return *source == '\0';
}

const char* reverseFind(const char* str, const char* from, char c)
{
	const char* tmp = from == nullptr ? nullptr : from - 1;
	if (tmp == nullptr)
	{
		tmp = str;
		while (*tmp)
		{
			++tmp;
		}
	}
	while (tmp >= str && *tmp != c)
	{
		--tmp;
	}
	if (tmp >= str)
	{
		return tmp;
	}
	return nullptr;
}

bool catNString(char* destination,
				int length,
				const char* source,
				int source_len)
{
	while (*destination && length)
	{
		--length;
		++destination;
	}
	return copyNString(destination, length, source, source_len);
}

bool catString(char* destination, int length, const char* source)
{
	while (*destination && length)
	{
		--length;
		++destination;
	}
	return copyString(destination, length, source);
}

static void reverse(char* str, int length)
{
	char* beg = str;
	char* end = str + length - 1;
	while (beg < end)
	{
		char tmp = *beg;
		*beg = *end;
		*end = tmp;
		++beg;
		--end;
	}
}

const char* fromCString(const char* input, int length, int32* value)
{
	int64 val;
	const char* ret = fromCString(input, length, &val);
	*value = (int32)val;
	return ret;
}

const char* fromCString(const char* input, int length, int64* value)
{
	if (length > 0)
	{
		const char* c = input;
		*value = 0;
		if (*c == '-')
		{
			++c;
			--length;
			if (!length)
			{
				return nullptr;
			}
		}
		while (length && *c >= '0' && *c <= '9')
		{
			*value *= 10;
			*value += *c - '0';
			++c;
			--length;
		}
		if (input[0] == '-')
		{
			*value = -*value;
		}
		return c;
	}
	return nullptr;
}

const char* fromCString(const char* input, int length, uint32* value)
{
	if (length > 0)
	{
		const char* c = input;
		*value = 0;
		if (*c == '-')
		{
			return nullptr;
		}
		while (length && *c >= '0' && *c <= '9')
		{
			*value *= 10;
			*value += *c - '0';
			++c;
			--length;
		}
		return c;
	}
	return nullptr;
}

bool toCStringPretty(int32 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCStringPretty((unsigned int)value, c, length);
	}
	return false;
}

bool toCStringPretty(uint32 value, char* output, int length)
{
	return toCStringPretty(uint64(value), output, length);
}

bool toCStringPretty(uint64 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		int counter = 0;
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
			if ((counter + 1) % 3 == 0 && length > 1 && value > 0)
			{
				*c = ' ';
				++c;
				counter = 0;
			}
			else
			{
				++counter;
			}
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

bool toCString(int32 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCString((unsigned int)value, c, length);
	}
	return false;
}

bool toCString(int64 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCString((uint64)value, c, length);
	}
	return false;
}

bool toCString(uint64 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

bool toCStringHex(uint8 value, char* output, int length)
{
	if (length < 2)
	{
		return false;
	}
	uint8 first = value / 16;
	if (first > 9)
	{
		output[0] = 'A' + first - 10;
	}
	else
	{
		output[0] = '0' + first;
	}
	uint8 second = value % 16;
	if (second > 9)
	{
		output[1] = 'A' + second - 10;
	}
	else
	{
		output[1] = '0' + second;
	}
	return true;
}

bool toCString(uint32 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

static bool increment(char* output, char* end, bool is_space_after)
{
	char carry = 1;
	char* c = end;
	while (c >= output)
	{
		if (*c == '.')
		{
			--c;
		}
		*c += carry;
		if (*c > '9')
		{
			*c = '0';
			carry = 1;
		}
		else
		{
			carry = 0;
			break;
		}
		--c;
	}
	if (carry && is_space_after)
	{
		char* c = end + 1; // including '\0' at the end of the string
		while (c >= output)
		{
			*(c + 1) = *c;
			++c;
		}
		*c = '1';
		return true;
	}
	return !carry;
}

bool toCString(float value, char* output, int length, int after_point)
{
	if (length < 2)
	{
		return false;
	}
	if (value < 0)
	{
		*output = '-';
		++output;
		value = -value;
		--length;
	}
	// int part
	int exponent = value == 0 ? 0 : (int)log10(value);
	float num = value;
	char* c = output;
	if (num  < 1 && num > -1 && length > 1)
	{
		*c = '0';
		++c;
		--length;
	}
	else
	{
		while ((num >= 1 || exponent >= 0) && length > 1)
		{
			float power = (float)pow(10, exponent);
			char digit = (char)floor(num / power);
			num -= digit * power;
			*c = digit + '0';
			--exponent;
			--length;
			++c;
		}
	}
	// decimal part
	float dec_part = num;
	if (length > 1 && after_point > 0)
	{
		*c = '.';
		++c;
		--length;
	}
	else if (length > 0 && after_point == 0)
	{
		*c = 0;
		return true;
	}
	else
	{
		return false;
	}
	while (length > 1 && after_point > 0)
	{
		dec_part *= 10;
		char tmp = (char)dec_part;
		*c = tmp + '0';
		dec_part -= tmp;
		++c;
		--length;
		--after_point;
	}
	*c = 0;
	if ((int)(dec_part + 0.5f))
		increment(output, c - 1, length > 1);
	return true;
}

char* trimmed(char* str)
{
	while (*str && (*str == '\t' || *str == ' '))
	{
		++str;
	}
	return str;
}

bool startsWith(const char* str, const char* prefix)
{
	const char* lhs = str;
	const char* rhs = prefix;
	while (*rhs && *lhs && *lhs == *rhs)
	{
		++lhs;
		++rhs;
	}

	return *rhs == 0;
}

} // ~namespace Lumix
<commit_msg>fixed crash when converting number such as 9.999 to string<commit_after>#include "string.h"
#include <cstring>
#include <cmath>

namespace Lumix
{

static char makeLowercase(char c)
{
	return c >= 'A' && c <= 'Z' ? c - ('A' - 'a') : c;
}

int compareMemory(const void* lhs, const void* rhs, size_t size)
{
	return memcmp(lhs, rhs, size);
}

int compareStringN(const char* lhs, const char* rhs, int length)
{
	return strncmp(lhs, rhs, length);
}

int compareIStringN(const char* lhs, const char* rhs, int length)
{
#ifdef _WIN32
	return strnicmp(lhs, rhs, length);
#else
	return strncasecmp(lhs, rhs, length);
#endif
}

int compareString(const char* lhs, const char* rhs)
{
	return strcmp(lhs, rhs);
}

bool equalStrings(const char* lhs, const char* rhs)
{
	return strcmp(lhs, rhs) == 0;
}

int stringLength(const char* str)
{
	return (int)strlen(str);
}

void moveMemory(void* dest, const void* src, size_t count)
{
	memmove(dest, src, count);
}

void setMemory(void* ptr, uint8 value, size_t num)
{
	memset(ptr, value, num);
}

void copyMemory(void* dest, const void* src, size_t count)
{
	memcpy(dest, src, count);
}

bool endsWith(const char* str, const char* substr)
{
	int len = stringLength(str);
	int len2 = stringLength(substr);
	if (len2 > len) return false;
	return equalStrings(str + len - len2, substr);
}

const char* stristr(const char* haystack, const char* needle)
{
	const char* c = haystack;
	while (*c)
	{
		if (makeLowercase(*c) == makeLowercase(needle[0]))
		{
			const char* n = needle + 1;
			const char* c2 = c + 1;
			while (*n && *c2)
			{
				if (makeLowercase(*n) != makeLowercase(*c2)) break;
				++n;
				++c2;
			}
			if (*n == 0) return c;
		}
		++c;
	}
	return nullptr;
}

bool makeLowercase(char* destination, int length, const char* source)
{
	if (!source)
	{
		return false;
	}

	while (*source && length)
	{
		*destination = makeLowercase(*source);
		--length;
		++destination;
		++source;
	}
	if (length > 0)
	{
		*destination = 0;
		return true;
	}
	return false;
}

const char* findSubstring(const char* haystack, const char* needle)
{
	return strstr(haystack, needle);
}

bool copyNString(char* destination, int length, const char* source, int source_len)
{
	if (!source)
	{
		return false;
	}

	while (*source && length > 1 && source_len)
	{
		*destination = *source;
		--source_len;
		--length;
		++destination;
		++source;
	}
	if (length > 0)
	{
		*destination = 0;
		return *source == '\0' || source_len == 0;
	}
	return false;
}

bool copyString(char* destination, int length, const char* source)
{
	if (!source || length < 1)
	{
		return false;
	}

	while (*source && length > 1)
	{
		*destination = *source;
		--length;
		++destination;
		++source;
	}
	*destination = 0;
	return *source == '\0';
}

const char* reverseFind(const char* str, const char* from, char c)
{
	const char* tmp = from == nullptr ? nullptr : from - 1;
	if (tmp == nullptr)
	{
		tmp = str;
		while (*tmp)
		{
			++tmp;
		}
	}
	while (tmp >= str && *tmp != c)
	{
		--tmp;
	}
	if (tmp >= str)
	{
		return tmp;
	}
	return nullptr;
}

bool catNString(char* destination,
				int length,
				const char* source,
				int source_len)
{
	while (*destination && length)
	{
		--length;
		++destination;
	}
	return copyNString(destination, length, source, source_len);
}

bool catString(char* destination, int length, const char* source)
{
	while (*destination && length)
	{
		--length;
		++destination;
	}
	return copyString(destination, length, source);
}

static void reverse(char* str, int length)
{
	char* beg = str;
	char* end = str + length - 1;
	while (beg < end)
	{
		char tmp = *beg;
		*beg = *end;
		*end = tmp;
		++beg;
		--end;
	}
}

const char* fromCString(const char* input, int length, int32* value)
{
	int64 val;
	const char* ret = fromCString(input, length, &val);
	*value = (int32)val;
	return ret;
}

const char* fromCString(const char* input, int length, int64* value)
{
	if (length > 0)
	{
		const char* c = input;
		*value = 0;
		if (*c == '-')
		{
			++c;
			--length;
			if (!length)
			{
				return nullptr;
			}
		}
		while (length && *c >= '0' && *c <= '9')
		{
			*value *= 10;
			*value += *c - '0';
			++c;
			--length;
		}
		if (input[0] == '-')
		{
			*value = -*value;
		}
		return c;
	}
	return nullptr;
}

const char* fromCString(const char* input, int length, uint32* value)
{
	if (length > 0)
	{
		const char* c = input;
		*value = 0;
		if (*c == '-')
		{
			return nullptr;
		}
		while (length && *c >= '0' && *c <= '9')
		{
			*value *= 10;
			*value += *c - '0';
			++c;
			--length;
		}
		return c;
	}
	return nullptr;
}

bool toCStringPretty(int32 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCStringPretty((unsigned int)value, c, length);
	}
	return false;
}

bool toCStringPretty(uint32 value, char* output, int length)
{
	return toCStringPretty(uint64(value), output, length);
}

bool toCStringPretty(uint64 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		int counter = 0;
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
			if ((counter + 1) % 3 == 0 && length > 1 && value > 0)
			{
				*c = ' ';
				++c;
				counter = 0;
			}
			else
			{
				++counter;
			}
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

bool toCString(int32 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCString((unsigned int)value, c, length);
	}
	return false;
}

bool toCString(int64 value, char* output, int length)
{
	char* c = output;
	if (length > 0)
	{
		if (value < 0)
		{
			value = -value;
			--length;
			*c = '-';
			++c;
		}
		return toCString((uint64)value, c, length);
	}
	return false;
}

bool toCString(uint64 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

bool toCStringHex(uint8 value, char* output, int length)
{
	if (length < 2)
	{
		return false;
	}
	uint8 first = value / 16;
	if (first > 9)
	{
		output[0] = 'A' + first - 10;
	}
	else
	{
		output[0] = '0' + first;
	}
	uint8 second = value % 16;
	if (second > 9)
	{
		output[1] = 'A' + second - 10;
	}
	else
	{
		output[1] = '0' + second;
	}
	return true;
}

bool toCString(uint32 value, char* output, int length)
{
	char* c = output;
	char* num_start = output;
	if (length > 0)
	{
		if (value == 0)
		{
			if (length == 1)
			{
				return false;
			}
			*c = '0';
			*(c + 1) = 0;
			return true;
		}
		while (value > 0 && length > 1)
		{
			*c = value % 10 + '0';
			value = value / 10;
			--length;
			++c;
		}
		if (length > 0)
		{
			reverse(num_start, (int)(c - num_start));
			*c = 0;
			return true;
		}
	}
	return false;
}

static bool increment(char* output, char* end, bool is_space_after)
{
	char carry = 1;
	char* c = end;
	while (c >= output)
	{
		if (*c == '.')
		{
			--c;
		}
		*c += carry;
		if (*c > '9')
		{
			*c = '0';
			carry = 1;
		}
		else
		{
			carry = 0;
			break;
		}
		--c;
	}
	if (carry && is_space_after)
	{
		char* c = end + 1; // including '\0' at the end of the string
		while (c >= output)
		{
			*(c + 1) = *c;
			--c;
		}
		++c;
		*c = '1';
		return true;
	}
	return !carry;
}

bool toCString(float value, char* output, int length, int after_point)
{
	if (length < 2)
	{
		return false;
	}
	if (value < 0)
	{
		*output = '-';
		++output;
		value = -value;
		--length;
	}
	// int part
	int exponent = value == 0 ? 0 : (int)log10(value);
	float num = value;
	char* c = output;
	if (num  < 1 && num > -1 && length > 1)
	{
		*c = '0';
		++c;
		--length;
	}
	else
	{
		while ((num >= 1 || exponent >= 0) && length > 1)
		{
			float power = (float)pow(10, exponent);
			char digit = (char)floor(num / power);
			num -= digit * power;
			*c = digit + '0';
			--exponent;
			--length;
			++c;
		}
	}
	// decimal part
	float dec_part = num;
	if (length > 1 && after_point > 0)
	{
		*c = '.';
		++c;
		--length;
	}
	else if (length > 0 && after_point == 0)
	{
		*c = 0;
		return true;
	}
	else
	{
		return false;
	}
	while (length > 1 && after_point > 0)
	{
		dec_part *= 10;
		char tmp = (char)dec_part;
		*c = tmp + '0';
		dec_part -= tmp;
		++c;
		--length;
		--after_point;
	}
	*c = 0;
	if ((int)(dec_part + 0.5f))
		increment(output, c - 1, length > 1);
	return true;
}

char* trimmed(char* str)
{
	while (*str && (*str == '\t' || *str == ' '))
	{
		++str;
	}
	return str;
}

bool startsWith(const char* str, const char* prefix)
{
	const char* lhs = str;
	const char* rhs = prefix;
	while (*rhs && *lhs && *lhs == *rhs)
	{
		++lhs;
		++rhs;
	}

	return *rhs == 0;
}

} // ~namespace Lumix
<|endoftext|>


<commit_before>/*

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

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <string>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <cctype>
#include <algorithm>
#include <iostream>

#include <boost/optional.hpp>

#include "libtorrent/assert.hpp"

namespace libtorrent
{
	std::string unescape_string(std::string const& s)
	{
		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			if(*i == '+')
			{
				ret += ' ';
			}
			else if (*i != '%')
			{
				ret += *i;
			}
			else
			{
				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int high;
				if(*i >= '0' && *i <= '9') high = *i - '0';
				else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int low;
				if(*i >= '0' && *i <= '9') low = *i - '0';
				else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				ret += char(high * 16 + low);
			}
		}
		return ret;
	}

	std::string escape_string(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		// http://www.ietf.org/rfc/rfc2396.txt
		// section 2.3
		// some trackers seems to require that ' is escaped
//		static const char unreserved_chars[] = "-_.!~*'()";
		static const char unreserved_chars[] = "-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string escape_path(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		static const char unreserved_chars[] = "/-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = (std::min)(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32encode(std::string const& s)
	{
		static const char base32_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', '2', '3', '4', '5', '6', '7'
		};

		int input_output_mapping[] = {0, 2, 4, 5, 7, 8};

		unsigned char inbuf[5];
		unsigned char outbuf[8];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(5, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+5, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xf8) >> 3;
			outbuf[1] = ((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6);
			outbuf[2] = ((inbuf[1] & 0x3e) >> 1);
			outbuf[3] = ((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4);
			outbuf[4] = ((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7);
			outbuf[5] = ((inbuf[3] & 0x7c) >> 2);
			outbuf[6] = ((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5);
			outbuf[7] = inbuf[4] & 0x1f;

			// write output
			int num_out = input_output_mapping[available_input];
			for (int j = 0; j < num_out; ++j)
			{
				ret += base32_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 8 - num_out; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32decode(std::string const& s)
	{
		unsigned char inbuf[8];
		unsigned char outbuf[5];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(8, (int)std::distance(i, s.end()));

			int pad_start = 0;
			if (available_input < 8) pad_start = available_input;

			// clear input buffer
			std::fill(inbuf, inbuf+8, 0);
			for (int j = 0; j < available_input; ++j)
			{
				char in = std::toupper(*i++);
				if (in >= 'A' && in <= 'Z')
					inbuf[j] = in - 'A';
				else if (in >= '2' && in <= '7')
					inbuf[j] = in - '2' + ('Z' - 'A') + 1;
				else if (in == '=')
				{
					inbuf[j] = 0;
					if (pad_start == 0) pad_start = j;
				}
				else if (in == '1')
					inbuf[j] = 'I' - 'A';
				else
					return std::string();
				TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
			}

			// decode inbuf to outbuf
			outbuf[0] = inbuf[0] << 3;
			outbuf[0] |= inbuf[1] >> 2;
			outbuf[1] = (inbuf[1] & 0x3) << 6;
			outbuf[1] |= inbuf[2] << 1;
			outbuf[1] |= (inbuf[3] & 0x10) >> 4;
			outbuf[2] = (inbuf[3] & 0x0f) << 4;
			outbuf[2] |= (inbuf[4] & 0x1e) >> 1;
			outbuf[3] = (inbuf[4] & 0x01) << 7;
			outbuf[3] |= (inbuf[5] & 0x1f) << 2;
			outbuf[3] |= (inbuf[6] & 0x18) >> 3;
			outbuf[4] = (inbuf[6] & 0x07) << 5;
			outbuf[4] |= inbuf[7];

			int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
			int num_out = input_output_mapping[pad_start];

			// write output
			std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
		}
		return ret;
	}

	boost::optional<std::string> url_has_argument(
		std::string const& url, std::string argument)
	{
		size_t i = url.find('?');
		if (i == std::string::npos) return boost::optional<std::string>();
		++i;

		argument += '=';

		if (url.compare(i, argument.size(), argument) == 0)
		{
			size_t pos = i + argument.size();
			return url.substr(pos, url.find('&', pos) - pos);
		}
		argument.insert(0, "&");
		i = url.find(argument, i);
		if (i == std::string::npos) return boost::optional<std::string>();
		size_t pos = i + argument.size();
		return url.substr(pos, url.find('&', pos) - pos);
	}

	TORRENT_EXPORT std::string to_hex(std::string const& s)
	{
		std::string ret;
		char* digits = "0123456789abcdef";
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			ret += digits[((unsigned char)*i) >> 4];
			ret += digits[((unsigned char)*i) & 0xf];
		}
		return ret;
	}

}

<commit_msg>fixed illegal type conversion<commit_after>/*

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

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <string>
#include <stdexcept>
#include <sstream>
#include <iomanip>
#include <cctype>
#include <algorithm>
#include <iostream>

#include <boost/optional.hpp>

#include "libtorrent/assert.hpp"

namespace libtorrent
{
	std::string unescape_string(std::string const& s)
	{
		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			if(*i == '+')
			{
				ret += ' ';
			}
			else if (*i != '%')
			{
				ret += *i;
			}
			else
			{
				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int high;
				if(*i >= '0' && *i <= '9') high = *i - '0';
				else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				++i;
				if (i == s.end())
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				int low;
				if(*i >= '0' && *i <= '9') low = *i - '0';
				else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
				else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
				else
#ifdef BOOST_NO_EXCEPTIONS
					return ret;
#else
					throw std::runtime_error("invalid escaped string");
#endif

				ret += char(high * 16 + low);
			}
		}
		return ret;
	}

	std::string escape_string(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		// http://www.ietf.org/rfc/rfc2396.txt
		// section 2.3
		// some trackers seems to require that ' is escaped
//		static const char unreserved_chars[] = "-_.!~*'()";
		static const char unreserved_chars[] = "-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string escape_path(const char* str, int len)
	{
		TORRENT_ASSERT(str != 0);
		TORRENT_ASSERT(len >= 0);
		static const char unreserved_chars[] = "/-_.!~*()"
			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
			"0123456789";

		std::stringstream ret;
		ret << std::hex << std::setfill('0');
		for (int i = 0; i < len; ++i)
		{
			if (std::count(
					unreserved_chars
					, unreserved_chars+sizeof(unreserved_chars)-1
					, *str))
			{
				ret << *str;
			}
			else
			{
				ret << '%'
					<< std::setw(2)
					<< (int)static_cast<unsigned char>(*str);
			}
			++str;
		}
		return ret.str();
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = (std::min)(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32encode(std::string const& s)
	{
		static const char base32_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', '2', '3', '4', '5', '6', '7'
		};

		int input_output_mapping[] = {0, 2, 4, 5, 7, 8};

		unsigned char inbuf[5];
		unsigned char outbuf[8];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(5, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+5, 0);

			// read a chunk of input into inbuf
			std::copy(i, i + available_input, inbuf);
			i += available_input;

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xf8) >> 3;
			outbuf[1] = ((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6);
			outbuf[2] = ((inbuf[1] & 0x3e) >> 1);
			outbuf[3] = ((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4);
			outbuf[4] = ((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7);
			outbuf[5] = ((inbuf[3] & 0x7c) >> 2);
			outbuf[6] = ((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5);
			outbuf[7] = inbuf[4] & 0x1f;

			// write output
			int num_out = input_output_mapping[available_input];
			for (int j = 0; j < num_out; ++j)
			{
				ret += base32_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 8 - num_out; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	std::string base32decode(std::string const& s)
	{
		unsigned char inbuf[8];
		unsigned char outbuf[5];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			int available_input = (std::min)(8, (int)std::distance(i, s.end()));

			int pad_start = 0;
			if (available_input < 8) pad_start = available_input;

			// clear input buffer
			std::fill(inbuf, inbuf+8, 0);
			for (int j = 0; j < available_input; ++j)
			{
				char in = std::toupper(*i++);
				if (in >= 'A' && in <= 'Z')
					inbuf[j] = in - 'A';
				else if (in >= '2' && in <= '7')
					inbuf[j] = in - '2' + ('Z' - 'A') + 1;
				else if (in == '=')
				{
					inbuf[j] = 0;
					if (pad_start == 0) pad_start = j;
				}
				else if (in == '1')
					inbuf[j] = 'I' - 'A';
				else
					return std::string();
				TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
			}

			// decode inbuf to outbuf
			outbuf[0] = inbuf[0] << 3;
			outbuf[0] |= inbuf[1] >> 2;
			outbuf[1] = (inbuf[1] & 0x3) << 6;
			outbuf[1] |= inbuf[2] << 1;
			outbuf[1] |= (inbuf[3] & 0x10) >> 4;
			outbuf[2] = (inbuf[3] & 0x0f) << 4;
			outbuf[2] |= (inbuf[4] & 0x1e) >> 1;
			outbuf[3] = (inbuf[4] & 0x01) << 7;
			outbuf[3] |= (inbuf[5] & 0x1f) << 2;
			outbuf[3] |= (inbuf[6] & 0x18) >> 3;
			outbuf[4] = (inbuf[6] & 0x07) << 5;
			outbuf[4] |= inbuf[7];

			int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
			int num_out = input_output_mapping[pad_start];

			// write output
			std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
		}
		return ret;
	}

	boost::optional<std::string> url_has_argument(
		std::string const& url, std::string argument)
	{
		size_t i = url.find('?');
		if (i == std::string::npos) return boost::optional<std::string>();
		++i;

		argument += '=';

		if (url.compare(i, argument.size(), argument) == 0)
		{
			size_t pos = i + argument.size();
			return url.substr(pos, url.find('&', pos) - pos);
		}
		argument.insert(0, "&");
		i = url.find(argument, i);
		if (i == std::string::npos) return boost::optional<std::string>();
		size_t pos = i + argument.size();
		return url.substr(pos, url.find('&', pos) - pos);
	}

	TORRENT_EXPORT std::string to_hex(std::string const& s)
	{
		std::string ret;
		char const* digits = "0123456789abcdef";
		for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
		{
			ret += digits[((unsigned char)*i) >> 4];
			ret += digits[((unsigned char)*i) & 0xf];
		}
		return ret;
	}

}

<|endoftext|>


<commit_before>//===- unittests/LockFileManagerTest.cpp - LockFileManager tests ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
#include <memory>

using namespace llvm;

namespace {

TEST(LockFileManagerTest, Basic) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  SmallString<64> LockedFile(TmpDir);
  sys::path::append(LockedFile, "file.lock");

  {
    // The lock file should not exist, so we should successfully acquire it.
    LockFileManager Locked1(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked1.getState());

    // Attempting to reacquire the lock should fail.  Waiting on it would cause
    // deadlock, so don't try that.
    LockFileManager Locked2(LockedFile);
    EXPECT_NE(LockFileManager::LFS_Owned, Locked2.getState());
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));

  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);
}

TEST(LockFileManagerTest, LinkLockExists) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  SmallString<64> LockedFile(TmpDir);
  sys::path::append(LockedFile, "file");

  SmallString<64> FileLocK(TmpDir);
  sys::path::append(FileLocK, "file.lock");

  SmallString<64> TmpFileLock(TmpDir);
  sys::path::append(TmpFileLock, "file.lock-000");

  EC = sys::fs::create_link(TmpFileLock.str(), FileLocK.str());
  ASSERT_FALSE(EC);

  {
    // The lock file doesn't point to a real file, so we should successfully
    // acquire it.
    LockFileManager Locked(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));

  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);
}

TEST(LockFileManagerTest, RelativePath) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  char PathBuf[1024];
  const char *OrigPath = getcwd(PathBuf, 1024);
  chdir(TmpDir.c_str());

  sys::fs::create_directory("inner");
  SmallString<64> LockedFile("inner");
  sys::path::append(LockedFile, "file");

  SmallString<64> FileLock(LockedFile);
  FileLock += ".lock";

  {
    // The lock file should not exist, so we should successfully acquire it.
    LockFileManager Locked(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
    EXPECT_TRUE(sys::fs::exists(FileLock.str()));
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(LockedFile.str()));
  EXPECT_FALSE(sys::fs::exists(FileLock.str()));

  EC = sys::fs::remove("inner");
  ASSERT_FALSE(EC);
  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);

  chdir(OrigPath);
}

} // end anonymous namespace
<commit_msg>Suppress SupportTests.LockFileManagerTest on win32 for investigating.<commit_after>//===- unittests/LockFileManagerTest.cpp - LockFileManager tests ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "gtest/gtest.h"
#include <memory>

using namespace llvm;

namespace {

TEST(LockFileManagerTest, Basic) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  SmallString<64> LockedFile(TmpDir);
  sys::path::append(LockedFile, "file.lock");

  {
    // The lock file should not exist, so we should successfully acquire it.
    LockFileManager Locked1(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked1.getState());

    // Attempting to reacquire the lock should fail.  Waiting on it would cause
    // deadlock, so don't try that.
    LockFileManager Locked2(LockedFile);
    EXPECT_NE(LockFileManager::LFS_Owned, Locked2.getState());
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));

  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);
}

#if !defined(_WIN32)
TEST(LockFileManagerTest, LinkLockExists) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  SmallString<64> LockedFile(TmpDir);
  sys::path::append(LockedFile, "file");

  SmallString<64> FileLocK(TmpDir);
  sys::path::append(FileLocK, "file.lock");

  SmallString<64> TmpFileLock(TmpDir);
  sys::path::append(TmpFileLock, "file.lock-000");

  EC = sys::fs::create_link(TmpFileLock.str(), FileLocK.str());
  ASSERT_FALSE(EC);

  {
    // The lock file doesn't point to a real file, so we should successfully
    // acquire it.
    LockFileManager Locked(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(StringRef(LockedFile)));

  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);
}

TEST(LockFileManagerTest, RelativePath) {
  SmallString<64> TmpDir;
  error_code EC;
  EC = sys::fs::createUniqueDirectory("LockFileManagerTestDir", TmpDir);
  ASSERT_FALSE(EC);

  char PathBuf[1024];
  const char *OrigPath = getcwd(PathBuf, 1024);
  chdir(TmpDir.c_str());

  sys::fs::create_directory("inner");
  SmallString<64> LockedFile("inner");
  sys::path::append(LockedFile, "file");

  SmallString<64> FileLock(LockedFile);
  FileLock += ".lock";

  {
    // The lock file should not exist, so we should successfully acquire it.
    LockFileManager Locked(LockedFile);
    EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
    EXPECT_TRUE(sys::fs::exists(FileLock.str()));
  }

  // Now that the lock is out of scope, the file should be gone.
  EXPECT_FALSE(sys::fs::exists(LockedFile.str()));
  EXPECT_FALSE(sys::fs::exists(FileLock.str()));

  EC = sys::fs::remove("inner");
  ASSERT_FALSE(EC);
  EC = sys::fs::remove(StringRef(TmpDir));
  ASSERT_FALSE(EC);

  chdir(OrigPath);
}
#endif

} // end anonymous namespace
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "Core/Transform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PathV1.h"

using namespace clang;

class DummyTransform : public Transform {
public:
  DummyTransform(llvm::StringRef Name, const TransformOptions &Options)
      : Transform(Name, Options) {}

  virtual int apply(const FileOverrides &,
                    const tooling::CompilationDatabase &,
                    const std::vector<std::string> &,
                    FileOverrides &) { return 0; }

  void setAcceptedChanges(unsigned Changes) {
    Transform::setAcceptedChanges(Changes);
  }
  void setRejectedChanges(unsigned Changes) {
    Transform::setRejectedChanges(Changes);
  }
  void setDeferredChanges(unsigned Changes) {
    Transform::setDeferredChanges(Changes);
  }
};

TEST(Transform, Interface) {
  TransformOptions Options;
  DummyTransform T("my_transform", Options);

  ASSERT_EQ("my_transform", T.getName());
  ASSERT_EQ(0u, T.getAcceptedChanges());
  ASSERT_EQ(0u, T.getRejectedChanges());
  ASSERT_EQ(0u, T.getDeferredChanges());
  ASSERT_FALSE(T.getChangesMade());
  ASSERT_FALSE(T.getChangesNotMade());

  T.setAcceptedChanges(1);
  ASSERT_TRUE(T.getChangesMade());

  T.setDeferredChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());

  T.setRejectedChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());

  T.Reset();
  ASSERT_EQ(0u, T.getAcceptedChanges());
  ASSERT_EQ(0u, T.getRejectedChanges());
  ASSERT_EQ(0u, T.getDeferredChanges());

  T.setRejectedChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());
}

class FindTopLevelDeclConsumer : public ASTConsumer {
public:
  FindTopLevelDeclConsumer(bool *Called) : Called(Called) {}

  virtual bool HandleTopLevelDecl(DeclGroupRef DeclGroup) {
    llvm::sys::TimeValue UserStart;
    llvm::sys::TimeValue SystemStart;
    llvm::sys::TimeValue UserNow;
    llvm::sys::TimeValue SystemNow;
    llvm::sys::TimeValue Wall;

    // Busy-wait until the user/system time combined is more than 1ms
    llvm::sys::TimeValue OneMS(0, 1000000);
    llvm::sys::Process::GetTimeUsage(Wall, UserStart, SystemStart);
    do {
      llvm::sys::Process::GetTimeUsage(Wall, UserNow, SystemNow);
    } while (UserNow - UserStart + SystemNow - SystemStart < OneMS);
    *Called = true;
    return true;
  }
  bool *Called;
};

struct ConsumerFactory {
  ASTConsumer *newASTConsumer() {
    return new FindTopLevelDeclConsumer(&Called);
  }
  bool Called;
};

TEST(Transform, Timings) {
  TransformOptions Options;
  Options.EnableTiming = true;
  DummyTransform T("timing_transform", Options);

  // All the path stuff is to make the test work independently of OS.

  // The directory used is not important since the path gets mapped to a virtual
  // file anyway. What is important is that we have an absolute path with which
  // to use with mapVirtualFile().
  llvm::sys::Path FileA = llvm::sys::Path::GetCurrentDirectory();
  std::string CurrentDir = FileA.str();
  FileA.appendComponent("a.cc");
  std::string FileAName = FileA.str();
  llvm::sys::Path FileB = llvm::sys::Path::GetCurrentDirectory();
  FileB.appendComponent("b.cc");
  std::string FileBName = FileB.str();

  tooling::FixedCompilationDatabase Compilations(CurrentDir, std::vector<std::string>());
  std::vector<std::string> Sources;
  Sources.push_back(FileAName);
  Sources.push_back(FileBName);
  tooling::ClangTool Tool(Compilations, Sources);

  Tool.mapVirtualFile(FileAName, "void a() {}");
  Tool.mapVirtualFile(FileBName, "void b() {}");

  ConsumerFactory Factory;
  Tool.run(newFrontendActionFactory(&Factory, &T));

  EXPECT_TRUE(Factory.Called);
  Transform::TimingVec::const_iterator I = T.timing_begin();
  EXPECT_GT(I->second.getProcessTime(), 0.0);

  // The success of the test shouldn't depend on the order of iteration through
  // timers.
  llvm::sys::Path FirstFile(I->first);
  if (FileA == FirstFile) {
    ++I;
    EXPECT_EQ(FileB, llvm::sys::Path(I->first));
    EXPECT_GT(I->second.getProcessTime(), 0.0);
  } else if (FileB == FirstFile) {
    ++I;
    EXPECT_EQ(FileA, llvm::sys::Path(I->first));
    EXPECT_GT(I->second.getProcessTime(), 0.0);
  } else {
    FAIL() << "Unexpected file name " << I->first << " in timing data.";
  }
  ++I;
  EXPECT_EQ(T.timing_end(), I);
}
<commit_msg>sys::Path::GetCurrentDirectory has been removed. Use sys::fs::current_path.<commit_after>#include "gtest/gtest.h"
#include "Core/Transform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PathV1.h"

using namespace clang;

class DummyTransform : public Transform {
public:
  DummyTransform(llvm::StringRef Name, const TransformOptions &Options)
      : Transform(Name, Options) {}

  virtual int apply(const FileOverrides &,
                    const tooling::CompilationDatabase &,
                    const std::vector<std::string> &,
                    FileOverrides &) { return 0; }

  void setAcceptedChanges(unsigned Changes) {
    Transform::setAcceptedChanges(Changes);
  }
  void setRejectedChanges(unsigned Changes) {
    Transform::setRejectedChanges(Changes);
  }
  void setDeferredChanges(unsigned Changes) {
    Transform::setDeferredChanges(Changes);
  }
};

TEST(Transform, Interface) {
  TransformOptions Options;
  DummyTransform T("my_transform", Options);

  ASSERT_EQ("my_transform", T.getName());
  ASSERT_EQ(0u, T.getAcceptedChanges());
  ASSERT_EQ(0u, T.getRejectedChanges());
  ASSERT_EQ(0u, T.getDeferredChanges());
  ASSERT_FALSE(T.getChangesMade());
  ASSERT_FALSE(T.getChangesNotMade());

  T.setAcceptedChanges(1);
  ASSERT_TRUE(T.getChangesMade());

  T.setDeferredChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());

  T.setRejectedChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());

  T.Reset();
  ASSERT_EQ(0u, T.getAcceptedChanges());
  ASSERT_EQ(0u, T.getRejectedChanges());
  ASSERT_EQ(0u, T.getDeferredChanges());

  T.setRejectedChanges(1);
  ASSERT_TRUE(T.getChangesNotMade());
}

class FindTopLevelDeclConsumer : public ASTConsumer {
public:
  FindTopLevelDeclConsumer(bool *Called) : Called(Called) {}

  virtual bool HandleTopLevelDecl(DeclGroupRef DeclGroup) {
    llvm::sys::TimeValue UserStart;
    llvm::sys::TimeValue SystemStart;
    llvm::sys::TimeValue UserNow;
    llvm::sys::TimeValue SystemNow;
    llvm::sys::TimeValue Wall;

    // Busy-wait until the user/system time combined is more than 1ms
    llvm::sys::TimeValue OneMS(0, 1000000);
    llvm::sys::Process::GetTimeUsage(Wall, UserStart, SystemStart);
    do {
      llvm::sys::Process::GetTimeUsage(Wall, UserNow, SystemNow);
    } while (UserNow - UserStart + SystemNow - SystemStart < OneMS);
    *Called = true;
    return true;
  }
  bool *Called;
};

struct ConsumerFactory {
  ASTConsumer *newASTConsumer() {
    return new FindTopLevelDeclConsumer(&Called);
  }
  bool Called;
};

TEST(Transform, Timings) {
  TransformOptions Options;
  Options.EnableTiming = true;
  DummyTransform T("timing_transform", Options);

  // All the path stuff is to make the test work independently of OS.

  // The directory used is not important since the path gets mapped to a virtual
  // file anyway. What is important is that we have an absolute path with which
  // to use with mapVirtualFile().
  SmallString<128> CurrentDir;
  llvm::error_code EC = llvm::sys::fs::current_path(CurrentDir);
  EXPECT_FALSE(EC);

  SmallString<128> FileA = CurrentDir;
  llvm::sys::path::append(FileA, "a.cc");

  SmallString<128> FileB = CurrentDir;
  llvm::sys::path::append(FileB, "b.cc");

  tooling::FixedCompilationDatabase Compilations(CurrentDir.str(), std::vector<std::string>());
  std::vector<std::string> Sources;
  Sources.push_back(FileA.str());
  Sources.push_back(FileB.str());
  tooling::ClangTool Tool(Compilations, Sources);

  Tool.mapVirtualFile(FileA, "void a() {}");
  Tool.mapVirtualFile(FileB, "void b() {}");

  ConsumerFactory Factory;
  Tool.run(newFrontendActionFactory(&Factory, &T));

  EXPECT_TRUE(Factory.Called);
  Transform::TimingVec::const_iterator I = T.timing_begin();
  EXPECT_GT(I->second.getProcessTime(), 0.0);

  // The success of the test shouldn't depend on the order of iteration through
  // timers.
  llvm::sys::Path FirstFile(I->first);
  if (FileA == FirstFile.str()) {
    ++I;
    EXPECT_EQ(FileB, llvm::sys::Path(I->first).str());
    EXPECT_GT(I->second.getProcessTime(), 0.0);
  } else if (FileB == FirstFile.str()) {
    ++I;
    EXPECT_EQ(FileA, llvm::sys::Path(I->first).str());
    EXPECT_GT(I->second.getProcessTime(), 0.0);
  } else {
    FAIL() << "Unexpected file name " << I->first << " in timing data.";
  }
  ++I;
  EXPECT_EQ(T.timing_end(), I);
}
<|endoftext|>


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

#include    "../Debug/Assertions.h"
#include    "DelegatedIterator.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

#if     qDebug
            namespace  Private_ {
                template    <typename T>
                IteratorTracker<T>::~IteratorTracker ()
                {
                    Assert (*fCountRunning == 0);
                }
                template    <typename T>
                Iterator<T>     IteratorTracker<T>::MakeDelegatedIterator (const Iterator<T>& sourceIterator)
                {
                    return DelegatedIterator<T, shared_ptr<unsigned int>> (sourceIterator, fCountRunning);
                }
            }
#endif

            /*
             ********************************************************************************
             * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep *
             ********************************************************************************
             */
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            inline  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep (const CONTEXT_FOR_EACH_ITERATOR& contextForEachIterator)
                : _fContextForEachIterator (contextForEachIterator)
#if     qDebug
                , fIteratorTracker_ ()
#endif
            {
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            Iterator<T>   IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::MakeIterator (IteratorOwnerID suggestedOwner) const
            {
#if     qDebug
                return fIteratorTracker_.MakeDelegatedIterator (Iterator<T> (typename Iterator<T>::SharedIRepPtr (new NEW_ITERATOR_REP_TYPE (_fContextForEachIterator))));
#else
                return Iterator<T> (typename Iterator<T>::SharedIRepPtr (new NEW_ITERATOR_REP_TYPE (_fContextForEachIterator)));
#endif
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            size_t     IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::GetLength () const
            {
                size_t  n = 0;
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    n++;
                }
                return n;
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            bool  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::IsEmpty () const
            {
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    return false;
                }
                return true;
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            void  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::Apply (_APPLY_ARGTYPE doToElement) const
            {
                this->_Apply (doToElement);
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            Iterator<T>   IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                return this->_FindFirstThat (doToElement, suggestedOwner);
            }
#define qNotSureWhyWeNeedExtraTemplateDefsIsItMSFTBugOrMyMisunderstanding   1
#if     qNotSureWhyWeNeedExtraTemplateDefsIsItMSFTBugOrMyMisunderstanding
            template    <typename T>
            size_t     IterableFromIterator<T, void, void>::_Rep::GetLength () const
            {
                size_t  n = 0;
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    n++;
                }
                return n;
            }
            template    <typename T>
            bool  IterableFromIterator<T, void, void>::_Rep::IsEmpty () const
            {
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    return false;
                }
                return true;
            }
            template    <typename T>
            void  IterableFromIterator<T, void, void>::_Rep::Apply (_APPLY_ARGTYPE doToElement) const
            {
                this->_Apply (doToElement);
            }
            template    <typename T>
            Iterator<T>   IterableFromIterator<T, void, void>::_Rep::FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                return this->_FindFirstThat (doToElement, suggestedOwner);
            }
#endif

            /*
             ********************************************************************************
             **************************** MakeIterableFromIterator **************************
             ********************************************************************************
             */
            template    <typename   T>
            Iterable<T> MakeIterableFromIterator (const Iterator<T>& iterator)
            {
                struct   MyIterable_ : public Iterable<T> {
                    struct   Rep : public IterableFromIterator<T>::_Rep {
                        using   _SharedPtrIRep      = typename Iterable<T>::_SharedPtrIRep;
                        DECLARE_USE_BLOCK_ALLOCATION(Rep);
                        Iterator<T>   fOriginalIterator;
#if     qDebug
                        mutable Private_::IteratorTracker<T>    fIteratorTracker_;
#endif
                        Rep (const Iterator<T>& originalIterator)
                            : fOriginalIterator (originalIterator)
#if     qDebug
                            , fIteratorTracker_ ()
#endif
                        {
                        }
                        virtual Iterator<T>     MakeIterator (IteratorOwnerID suggestedOwner) const override
                        {
#if     qDebug
                            return fIteratorTracker_.MakeDelegatedIterator (fOriginalIterator);
#else
                            return fOriginalIterator;
#endif
                        }
                        virtual _SharedPtrIRep Clone (IteratorOwnerID forIterableEnvelope) const override
                        {
                            return _SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (*this));
                        }
                    };
                    MyIterable_ (const Iterator<T>& originalIterator)
                        : Iterable<T> (typename Iterable<T>::_SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (originalIterator)))
                    {
                    }
                };
                return MyIterable_ (iterator);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_IterableFromIterator_inl_ */
<commit_msg>workaround maybe misnamed qCompilerAndStdLib_SFINAE_SharedPtr_Buggy for gcc<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_IterableFromIterator_inl_
#define _Stroika_Foundation_Traversal_IterableFromIterator_inl_

#include    "../Debug/Assertions.h"
#include    "DelegatedIterator.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

#if     qDebug
            namespace  Private_ {
                template    <typename T>
                IteratorTracker<T>::~IteratorTracker ()
                {
                    Assert (*fCountRunning == 0);
                }
                template    <typename T>
                Iterator<T>     IteratorTracker<T>::MakeDelegatedIterator (const Iterator<T>& sourceIterator)
                {
                    return DelegatedIterator<T, shared_ptr<unsigned int>> (sourceIterator, fCountRunning);
                }
            }
#endif

            /*
             ********************************************************************************
             * IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep *
             ********************************************************************************
             */
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            inline  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::_Rep (const CONTEXT_FOR_EACH_ITERATOR& contextForEachIterator)
                : _fContextForEachIterator (contextForEachIterator)
#if     qDebug
                , fIteratorTracker_ ()
#endif
            {
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            Iterator<T>   IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::MakeIterator (IteratorOwnerID suggestedOwner) const
            {
#if     qDebug
                return fIteratorTracker_.MakeDelegatedIterator (Iterator<T> (typename Iterator<T>::SharedIRepPtr (new NEW_ITERATOR_REP_TYPE (_fContextForEachIterator))));
#else
                return Iterator<T> (typename Iterator<T>::SharedIRepPtr (new NEW_ITERATOR_REP_TYPE (_fContextForEachIterator)));
#endif
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            size_t     IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::GetLength () const
            {
                size_t  n = 0;
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    n++;
                }
                return n;
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            bool  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::IsEmpty () const
            {
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    return false;
                }
                return true;
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            void  IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::Apply (_APPLY_ARGTYPE doToElement) const
            {
                this->_Apply (doToElement);
            }
            template    <typename T, typename NEW_ITERATOR_REP_TYPE, typename CONTEXT_FOR_EACH_ITERATOR>
            Iterator<T>   IterableFromIterator<T, NEW_ITERATOR_REP_TYPE, CONTEXT_FOR_EACH_ITERATOR>::_Rep::FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                return this->_FindFirstThat (doToElement, suggestedOwner);
            }
#define qNotSureWhyWeNeedExtraTemplateDefsIsItMSFTBugOrMyMisunderstanding   1
#if     qNotSureWhyWeNeedExtraTemplateDefsIsItMSFTBugOrMyMisunderstanding
            template    <typename T>
            size_t     IterableFromIterator<T, void, void>::_Rep::GetLength () const
            {
                size_t  n = 0;
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    n++;
                }
                return n;
            }
            template    <typename T>
            bool  IterableFromIterator<T, void, void>::_Rep::IsEmpty () const
            {
                for (auto i = this->MakeIterator (this); not i.Done (); ++i) {
                    return false;
                }
                return true;
            }
            template    <typename T>
            void  IterableFromIterator<T, void, void>::_Rep::Apply (_APPLY_ARGTYPE doToElement) const
            {
                this->_Apply (doToElement);
            }
            template    <typename T>
            Iterator<T>   IterableFromIterator<T, void, void>::_Rep::FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                return this->_FindFirstThat (doToElement, suggestedOwner);
            }
#endif

            /*
             ********************************************************************************
             **************************** MakeIterableFromIterator **************************
             ********************************************************************************
             */
#if     qCompilerAndStdLib_SFINAE_SharedPtr_Buggy
            {
                template    <typename   T>
                struct   MyIterable_ : public Iterable<T> {
                    struct   Rep : public IterableFromIterator<T>::_Rep {
                        using   _SharedPtrIRep      = typename Iterable<T>::_SharedPtrIRep;
                        DECLARE_USE_BLOCK_ALLOCATION(Rep);
                        Iterator<T>   fOriginalIterator;
#if     qDebug
                        mutable Private_::IteratorTracker<T>    fIteratorTracker_;
#endif
                        Rep (const Iterator<T>& originalIterator)
                            : fOriginalIterator (originalIterator)
#if     qDebug
                            , fIteratorTracker_ ()
#endif
                        {
                        }
                        virtual Iterator<T>     MakeIterator (IteratorOwnerID suggestedOwner) const override
                        {
#if     qDebug
                            return fIteratorTracker_.MakeDelegatedIterator (fOriginalIterator);
#else
                            return fOriginalIterator;
#endif
                        }
                        virtual _SharedPtrIRep Clone (IteratorOwnerID forIterableEnvelope) const override
                        {
                            return _SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (*this));
                        }
                    };
                    MyIterable_ (const Iterator<T>& originalIterator)
                        : Iterable<T> (typename Iterable<T>::_SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (originalIterator)))
                    {
                    }
                };
            }
#endif
            template    <typename   T>
            Iterable<T> MakeIterableFromIterator (const Iterator<T>& iterator)
            {
#if     !qCompilerAndStdLib_SFINAE_SharedPtr_Buggy
                struct   MyIterable_ : public Iterable<T> {
                    struct   Rep : public IterableFromIterator<T>::_Rep {
                        using   _SharedPtrIRep      = typename Iterable<T>::_SharedPtrIRep;
                        DECLARE_USE_BLOCK_ALLOCATION(Rep);
                        Iterator<T>   fOriginalIterator;
#if     qDebug
                        mutable Private_::IteratorTracker<T>    fIteratorTracker_;
#endif
                        Rep (const Iterator<T>& originalIterator)
                            : fOriginalIterator (originalIterator)
#if     qDebug
                            , fIteratorTracker_ ()
#endif
                        {
                        }
                        virtual Iterator<T>     MakeIterator (IteratorOwnerID suggestedOwner) const override
                        {
#if     qDebug
                            return fIteratorTracker_.MakeDelegatedIterator (fOriginalIterator);
#else
                            return fOriginalIterator;
#endif
                        }
                        virtual _SharedPtrIRep Clone (IteratorOwnerID forIterableEnvelope) const override
                        {
                            return _SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (*this));
                        }
                    };
                    MyIterable_ (const Iterator<T>& originalIterator)
                        : Iterable<T> (typename Iterable<T>::_SharedPtrIRep (Iterable<T>::template MakeSharedPtr<Rep> (originalIterator)))
                    {
                    }
                };
#endif
                return MyIterable_ (iterator);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_IterableFromIterator_inl_ */
<|endoftext|>