<commit_before>#include "stdafx.h"
#include "VersionChecker.h"
#include "Version.h"

#include <afxinet.h>
#include <memory>

void CVersionChecker::VersionCheckerThread()
{
	UINT totalBytesRead = 0;
	// The Version.h file is about 470 bytes.
	char buffer[1000];
	try
	{
		CInternetSession	MySession;
		const wchar_t* const url = L"https://raw.githubusercontent.com/google/UIforETW/master/UIforETW/VersionCopy.h";
		std::unique_ptr<CStdioFile> webFile(MySession.OpenURL(url));
		// Read into the buffer -- set the maximum to one less than the length
		// of the buffer.
		while (totalBytesRead < sizeof(buffer) - 1)
		{
			const UINT bytesRead = webFile->Read(buffer + totalBytesRead, sizeof(buffer) - 1 - totalBytesRead);
			if (!bytesRead)
				break;
			totalBytesRead += bytesRead;
		}
		webFile->Close();
	}
	catch (...)
	{
	}
	// Null terminate the buffer.
	buffer[totalBytesRead] = 0;
	const char* const marker = "const float kCurrentVersion = ";
	char* version_string = strstr(buffer, marker);
	if (version_string)
	{
		version_string += strlen(marker);
		if (strlen(version_string) > 4)
		{
			// String will be something like: "1.32f" and we want to cut off at 'f'.
			version_string[5] = 0;
			PackagedFloatVersion newVersion;
			newVersion.u = 0;
			if (sscanf_s(version_string, "%f", &newVersion.f) == 1)
			{
				if (newVersion.f > kCurrentVersion)
				{
					pWindow_->PostMessage(WM_NEWVERSIONAVAILABLE, newVersion.u);
				}
			}
		}
	}
}

DWORD __stdcall CVersionChecker::StaticVersionCheckerThread(LPVOID pParam)
{
	CVersionChecker* pThis = static_cast<CVersionChecker*>(pParam);
	pThis->VersionCheckerThread();
	return 0;
}

void CVersionChecker::StartVersionCheckerThread(CWnd* pWindow) noexcept
{
	pWindow_ = pWindow;
	hThread_ = CreateThread(nullptr, 0, StaticVersionCheckerThread, this, 0, nullptr);
}

CVersionChecker::CVersionChecker() noexcept
{
}

CVersionChecker::~CVersionChecker()
{
	if (hThread_)
	{
		WaitForSingleObject(hThread_, INFINITE);
		CloseHandle(hThread_);
	}
}
<commit_msg>Change branch used for version checking<commit_after>#include "stdafx.h"
#include "VersionChecker.h"
#include "Version.h"

#include <afxinet.h>
#include <memory>

void CVersionChecker::VersionCheckerThread()
{
	UINT totalBytesRead = 0;
	// The Version.h file is about 470 bytes.
	char buffer[1000];
	try
	{
		CInternetSession	MySession;
		const wchar_t* const url = L"https://raw.githubusercontent.com/google/UIforETW/main/UIforETW/VersionCopy.h";
		std::unique_ptr<CStdioFile> webFile(MySession.OpenURL(url));
		// Read into the buffer -- set the maximum to one less than the length
		// of the buffer.
		while (totalBytesRead < sizeof(buffer) - 1)
		{
			const UINT bytesRead = webFile->Read(buffer + totalBytesRead, sizeof(buffer) - 1 - totalBytesRead);
			if (!bytesRead)
				break;
			totalBytesRead += bytesRead;
		}
		webFile->Close();
	}
	catch (...)
	{
	}
	// Null terminate the buffer.
	buffer[totalBytesRead] = 0;
	const char* const marker = "const float kCurrentVersion = ";
	char* version_string = strstr(buffer, marker);
	if (version_string)
	{
		version_string += strlen(marker);
		if (strlen(version_string) > 4)
		{
			// String will be something like: "1.32f" and we want to cut off at 'f'.
			version_string[5] = 0;
			PackagedFloatVersion newVersion;
			newVersion.u = 0;
			if (sscanf_s(version_string, "%f", &newVersion.f) == 1)
			{
				if (newVersion.f > kCurrentVersion)
				{
					pWindow_->PostMessage(WM_NEWVERSIONAVAILABLE, newVersion.u);
				}
			}
		}
	}
}

DWORD __stdcall CVersionChecker::StaticVersionCheckerThread(LPVOID pParam)
{
	CVersionChecker* pThis = static_cast<CVersionChecker*>(pParam);
	pThis->VersionCheckerThread();
	return 0;
}

void CVersionChecker::StartVersionCheckerThread(CWnd* pWindow) noexcept
{
	pWindow_ = pWindow;
	hThread_ = CreateThread(nullptr, 0, StaticVersionCheckerThread, this, 0, nullptr);
}

CVersionChecker::CVersionChecker() noexcept
{
}

CVersionChecker::~CVersionChecker()
{
	if (hThread_)
	{
		WaitForSingleObject(hThread_, INFINITE);
		CloseHandle(hThread_);
	}
}
<|endoftext|>


<commit_before>
#pragma once

#include "geometry/rotation.hpp"

#include <algorithm>

#include "geometry/grassmann.hpp"
#include "geometry/linear_map.hpp"
#include "geometry/quaternion.hpp"
#include "geometry/r3_element.hpp"
#include "geometry/sign.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace geometry {

namespace {

// Well-conditioned conversion of a rotation matrix to a quaternion.  See
// http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion and
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/.
FORCE_INLINE Quaternion ToQuaternion(R3x3Matrix const& matrix) {
  // TODO(egg): this should probably contain some checks that |matrix| has
  // positive determinant...
  double const t = matrix.Trace();
  double real_part;
  R3Element<double> imaginary_part;
  if (t > 0) {
    double const r = sqrt(1.0 + t);
    double const s = 0.5 / r;
    real_part = 0.5 * r;
    imaginary_part.x = (matrix(2, 1) - matrix(1, 2)) * s;
    imaginary_part.y = (matrix(0, 2) - matrix(2, 0)) * s;
    imaginary_part.z = (matrix(1, 0) - matrix(0, 1)) * s;
  } else if (matrix(0, 0) > std::max(matrix(1, 1), matrix(2, 2))) {
    double const r =
        sqrt(1.0 + matrix(0, 0) - matrix(1, 1) - matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(2, 1) - matrix(1, 2)) * s;
    imaginary_part.x = 0.5 * r;
    imaginary_part.y = (matrix(0, 1) + matrix(1, 0)) * s;
    imaginary_part.z = (matrix(2, 0) + matrix(0, 2)) * s;
  } else if (matrix(1, 1) > matrix(2, 2)) {
    double const r =
        sqrt(1.0 - matrix(0, 0) + matrix(1, 1) - matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(0, 2) - matrix(2, 0)) * s;
    imaginary_part.x = (matrix(0, 1) + matrix(1, 0)) * s;
    imaginary_part.y = 0.5 * r;
    imaginary_part.z = (matrix(1, 2) + matrix(2, 1)) * s;
  } else {
    double const r =
        sqrt(1.0 - matrix(0, 0) - matrix(1, 1) + matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(1, 0) - matrix(0, 1)) * s;
    imaginary_part.x = (matrix(0, 2) + matrix(2, 0)) * s;
    imaginary_part.y = (matrix(1, 2) + matrix(2, 1)) * s;
    imaginary_part.z = 0.5 * r;
  }
  return Quaternion(real_part, imaginary_part);
}

// Returns a rotation of |angle| around |axis|.  |axis| must be normalized.
Quaternion AngleAxis(Angle const& angle, R3Element<double> const& axis) {
  quantities::Angle const half_angle = 0.5 * angle;
  return Quaternion(Cos(half_angle), Sin(half_angle) * axis);
}

// Returns a rotation of |angle| around the |axis_index|th axis.
Quaternion AngleAxis(Angle const& angle, int const axis_index) {
  R3Element<double> axis{0, 0, 0};
  axis[axis_index] = 1;
  return AngleAxis(angle, axis);
}

}  // namespace

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame>::Rotation(Quaternion const& quaternion)
    : quaternion_(quaternion) {}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(quantities::Angle const& angle,
                                       Bivector<Scalar, FromFrame> const& axis)
    : Rotation(AngleAxis(angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<int rank_x, int rank_y, int rank_z, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Multivector<double, FromFrame, rank_x> x_to_frame,
    Multivector<double, FromFrame, rank_y> y_to_frame,
    Multivector<double, FromFrame, rank_z> z_to_frame)
    : Rotation<FromFrame, ToFrame>(
          ToQuaternion(R3x3Matrix(x_to_frame.coordinates(),
                                  y_to_frame.coordinates(),
                                  z_to_frame.coordinates()))) {
  static_assert((rank_x + rank_y + rank_z) % 2 == 0, "chiral basis");
  static_assert(rank_x < 3 && rank_y < 3 && rank_z < 3, "bad dimension");
}

template<typename FromFrame, typename ToFrame>
template<int rank_x, int rank_y, int rank_z,
         typename F, typename T, typename, typename>  // typename and spam.
Rotation<FromFrame, ToFrame>::Rotation(
    Multivector<double, ToFrame, rank_x> x_from_frame,
    Multivector<double, ToFrame, rank_y> y_from_frame,
    Multivector<double, ToFrame, rank_z> z_from_frame)
    : Rotation<FromFrame, ToFrame>(
          ToQuaternion(R3x3Matrix(x_from_frame.coordinates(),
                                  y_from_frame.coordinates(),
                                  z_from_frame.coordinates()).Transpose())) {
  static_assert((rank_x + rank_y + rank_z) % 2 == 0, "chiral basis");
  static_assert(rank_x < 3 && rank_y < 3 && rank_z < 3, "bad dimension");
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(Angle const& angle,
                                       Bivector<Scalar, FromFrame> const& axis,
                                       DefinesFrame<ToFrame> tag)
    : Rotation(AngleAxis(-angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(Angle const& angle,
                                       Bivector<Scalar, ToFrame> const& axis,
                                       DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    EulerAngles const axes,
    DefinesFrame<ToFrame> tag)
    : Rotation(Rotation<ToFrame, FromFrame>(α, β, γ, axes, tag).Inverse()) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    EulerAngles const axes,
    DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(α, (static_cast<int>(axes) >> (2 * 2)) % 2) *
               AngleAxis(β, (static_cast<int>(axes) >> (2 * 1)) % 2) *
               AngleAxis(γ, (static_cast<int>(axes) >> (2 * 0)) % 2)) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    CardanAngles const axes,
    DefinesFrame<ToFrame> tag)
    : Rotation(Rotation<ToFrame, FromFrame>(α, β, γ, axes, tag).Inverse()) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    CardanAngles const axes,
    DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(α, (static_cast<int>(axes) >> (2 * 2)) % 2) *
               AngleAxis(β, (static_cast<int>(axes) >> (2 * 1)) % 2) *
               AngleAxis(γ, (static_cast<int>(axes) >> (2 * 0)) % 2)) {}

template<typename FromFrame, typename ToFrame>
Sign Rotation<FromFrame, ToFrame>::Determinant() const {
  return Sign(1);
}

template<typename FromFrame, typename ToFrame>
Rotation<ToFrame, FromFrame> Rotation<FromFrame, ToFrame>::Inverse() const {
  // Because |quaternion_| has norm 1, its inverse is just its conjugate.
  return Rotation<ToFrame, FromFrame>(quaternion_.Conjugate());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Vector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Vector<Scalar, FromFrame> const& vector) const {
  return Vector<Scalar, ToFrame>((*this)(vector.coordinates()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Bivector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Bivector<Scalar, FromFrame> const& bivector) const {
  return Bivector<Scalar, ToFrame>((*this)(bivector.coordinates()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Trivector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Trivector<Scalar, FromFrame> const& trivector) const {
  return trivector;
}

template<typename FromFrame, typename ToFrame>
template<typename T>
typename base::Mappable<Rotation<FromFrame, ToFrame>, T>::type
Rotation<FromFrame, ToFrame>::operator()(T const& t) const {
  return base::Mappable<Rotation, T>::Do(*this, t);
}

template<typename FromFrame, typename ToFrame>
OrthogonalMap<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::Forget() const {
  return OrthogonalMap<FromFrame, ToFrame>(Sign(1), *this);
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::Identity() {
  return Rotation(Quaternion(1));
}

template<typename FromFrame, typename ToFrame>
Quaternion const& Rotation<FromFrame, ToFrame>::quaternion() const {
  return quaternion_;
}

template<typename FromFrame, typename ToFrame>
void Rotation<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::LinearMap*> const message) const {
  LinearMap<FromFrame, ToFrame>::WriteToMessage(message);
  WriteToMessage(message->MutableExtension(serialization::Rotation::extension));
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::ReadFromMessage(
    serialization::LinearMap const& message) {
  LinearMap<FromFrame, ToFrame>::ReadFromMessage(message);
  CHECK(message.HasExtension(serialization::Rotation::extension));
  return ReadFromMessage(
      message.GetExtension(serialization::Rotation::extension));
}

template<typename FromFrame, typename ToFrame>
void Rotation<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::Rotation*> const message) const {
  quaternion_.WriteToMessage(message->mutable_quaternion());
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::ReadFromMessage(
    serialization::Rotation const& message) {
  return Rotation(Quaternion::ReadFromMessage(message.quaternion()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
R3Element<Scalar> Rotation<FromFrame, ToFrame>::operator()(
    R3Element<Scalar> const& r3_element) const {
  double const real_part = quaternion_.real_part();
  R3Element<double> const& imaginary_part = quaternion_.imaginary_part();
  return r3_element + 2 * Cross(imaginary_part,
                                Cross(imaginary_part, r3_element) +
                                      real_part * r3_element);
}

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> operator*(
    Rotation<ThroughFrame, ToFrame> const& left,
    Rotation<FromFrame, ThroughFrame> const& right) {
  return Rotation<FromFrame, ToFrame>(left.quaternion_ * right.quaternion_);
}

template<typename FromFrame, typename ToFrame>
std::ostream& operator<<(std::ostream& out,
                         Rotation<FromFrame, ToFrame> const& rotation) {
  return out << rotation.quaternion_;
}

}  // namespace geometry
}  // namespace principia
<commit_msg>I am bad at bit hackery<commit_after>
#pragma once

#include "geometry/rotation.hpp"

#include <algorithm>

#include "geometry/grassmann.hpp"
#include "geometry/linear_map.hpp"
#include "geometry/quaternion.hpp"
#include "geometry/r3_element.hpp"
#include "geometry/sign.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace geometry {

namespace {

// Well-conditioned conversion of a rotation matrix to a quaternion.  See
// http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion and
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/.
FORCE_INLINE Quaternion ToQuaternion(R3x3Matrix const& matrix) {
  // TODO(egg): this should probably contain some checks that |matrix| has
  // positive determinant...
  double const t = matrix.Trace();
  double real_part;
  R3Element<double> imaginary_part;
  if (t > 0) {
    double const r = sqrt(1.0 + t);
    double const s = 0.5 / r;
    real_part = 0.5 * r;
    imaginary_part.x = (matrix(2, 1) - matrix(1, 2)) * s;
    imaginary_part.y = (matrix(0, 2) - matrix(2, 0)) * s;
    imaginary_part.z = (matrix(1, 0) - matrix(0, 1)) * s;
  } else if (matrix(0, 0) > std::max(matrix(1, 1), matrix(2, 2))) {
    double const r =
        sqrt(1.0 + matrix(0, 0) - matrix(1, 1) - matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(2, 1) - matrix(1, 2)) * s;
    imaginary_part.x = 0.5 * r;
    imaginary_part.y = (matrix(0, 1) + matrix(1, 0)) * s;
    imaginary_part.z = (matrix(2, 0) + matrix(0, 2)) * s;
  } else if (matrix(1, 1) > matrix(2, 2)) {
    double const r =
        sqrt(1.0 - matrix(0, 0) + matrix(1, 1) - matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(0, 2) - matrix(2, 0)) * s;
    imaginary_part.x = (matrix(0, 1) + matrix(1, 0)) * s;
    imaginary_part.y = 0.5 * r;
    imaginary_part.z = (matrix(1, 2) + matrix(2, 1)) * s;
  } else {
    double const r =
        sqrt(1.0 - matrix(0, 0) - matrix(1, 1) + matrix(2, 2));
    double const s = 0.5 / r;
    real_part = (matrix(1, 0) - matrix(0, 1)) * s;
    imaginary_part.x = (matrix(0, 2) + matrix(2, 0)) * s;
    imaginary_part.y = (matrix(1, 2) + matrix(2, 1)) * s;
    imaginary_part.z = 0.5 * r;
  }
  return Quaternion(real_part, imaginary_part);
}

// Returns a rotation of |angle| around |axis|.  |axis| must be normalized.
Quaternion AngleAxis(Angle const& angle, R3Element<double> const& axis) {
  quantities::Angle const half_angle = 0.5 * angle;
  return Quaternion(Cos(half_angle), Sin(half_angle) * axis);
}

// Returns a rotation of |angle| around the |axis_index|th axis.
Quaternion AngleAxis(Angle const& angle, int const axis_index) {
  R3Element<double> axis{0, 0, 0};
  axis[axis_index] = 1;
  return AngleAxis(angle, axis);
}

}  // namespace

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame>::Rotation(Quaternion const& quaternion)
    : quaternion_(quaternion) {}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(quantities::Angle const& angle,
                                       Bivector<Scalar, FromFrame> const& axis)
    : Rotation(AngleAxis(angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<int rank_x, int rank_y, int rank_z, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Multivector<double, FromFrame, rank_x> x_to_frame,
    Multivector<double, FromFrame, rank_y> y_to_frame,
    Multivector<double, FromFrame, rank_z> z_to_frame)
    : Rotation<FromFrame, ToFrame>(
          ToQuaternion(R3x3Matrix(x_to_frame.coordinates(),
                                  y_to_frame.coordinates(),
                                  z_to_frame.coordinates()))) {
  static_assert((rank_x + rank_y + rank_z) % 2 == 0, "chiral basis");
  static_assert(rank_x < 3 && rank_y < 3 && rank_z < 3, "bad dimension");
}

template<typename FromFrame, typename ToFrame>
template<int rank_x, int rank_y, int rank_z,
         typename F, typename T, typename, typename>  // typename and spam.
Rotation<FromFrame, ToFrame>::Rotation(
    Multivector<double, ToFrame, rank_x> x_from_frame,
    Multivector<double, ToFrame, rank_y> y_from_frame,
    Multivector<double, ToFrame, rank_z> z_from_frame)
    : Rotation<FromFrame, ToFrame>(
          ToQuaternion(R3x3Matrix(x_from_frame.coordinates(),
                                  y_from_frame.coordinates(),
                                  z_from_frame.coordinates()).Transpose())) {
  static_assert((rank_x + rank_y + rank_z) % 2 == 0, "chiral basis");
  static_assert(rank_x < 3 && rank_y < 3 && rank_z < 3, "bad dimension");
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(Angle const& angle,
                                       Bivector<Scalar, FromFrame> const& axis,
                                       DefinesFrame<ToFrame> tag)
    : Rotation(AngleAxis(-angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<typename Scalar, typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(Angle const& angle,
                                       Bivector<Scalar, ToFrame> const& axis,
                                       DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(angle, Normalize(axis).coordinates())) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    EulerAngles const axes,
    DefinesFrame<ToFrame> tag)
    : Rotation(Rotation<ToFrame, FromFrame>(α, β, γ, axes, tag).Inverse()) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    EulerAngles const axes,
    DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(α, (static_cast<int>(axes) >> (2 * 2)) & 0b11) *
               AngleAxis(β, (static_cast<int>(axes) >> (2 * 1)) & 0b11) *
               AngleAxis(γ, (static_cast<int>(axes) >> (2 * 0)) & 0b11)) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    CardanAngles const axes,
    DefinesFrame<ToFrame> tag)
    : Rotation(Rotation<ToFrame, FromFrame>(α, β, γ, axes, tag).Inverse()) {}

template<typename FromFrame, typename ToFrame>
template<typename F, typename T, typename, typename>
Rotation<FromFrame, ToFrame>::Rotation(
    Angle const& α,
    Angle const& β,
    Angle const& γ,
    CardanAngles const axes,
    DefinesFrame<FromFrame> tag)
    : Rotation(AngleAxis(α, (static_cast<int>(axes) >> (2 * 2)) & 0b11) *
               AngleAxis(β, (static_cast<int>(axes) >> (2 * 1)) & 0b11) *
               AngleAxis(γ, (static_cast<int>(axes) >> (2 * 0)) & 0b11)) {}

template<typename FromFrame, typename ToFrame>
Sign Rotation<FromFrame, ToFrame>::Determinant() const {
  return Sign(1);
}

template<typename FromFrame, typename ToFrame>
Rotation<ToFrame, FromFrame> Rotation<FromFrame, ToFrame>::Inverse() const {
  // Because |quaternion_| has norm 1, its inverse is just its conjugate.
  return Rotation<ToFrame, FromFrame>(quaternion_.Conjugate());
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Vector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Vector<Scalar, FromFrame> const& vector) const {
  return Vector<Scalar, ToFrame>((*this)(vector.coordinates()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Bivector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Bivector<Scalar, FromFrame> const& bivector) const {
  return Bivector<Scalar, ToFrame>((*this)(bivector.coordinates()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
Trivector<Scalar, ToFrame> Rotation<FromFrame, ToFrame>::operator()(
    Trivector<Scalar, FromFrame> const& trivector) const {
  return trivector;
}

template<typename FromFrame, typename ToFrame>
template<typename T>
typename base::Mappable<Rotation<FromFrame, ToFrame>, T>::type
Rotation<FromFrame, ToFrame>::operator()(T const& t) const {
  return base::Mappable<Rotation, T>::Do(*this, t);
}

template<typename FromFrame, typename ToFrame>
OrthogonalMap<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::Forget() const {
  return OrthogonalMap<FromFrame, ToFrame>(Sign(1), *this);
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::Identity() {
  return Rotation(Quaternion(1));
}

template<typename FromFrame, typename ToFrame>
Quaternion const& Rotation<FromFrame, ToFrame>::quaternion() const {
  return quaternion_;
}

template<typename FromFrame, typename ToFrame>
void Rotation<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::LinearMap*> const message) const {
  LinearMap<FromFrame, ToFrame>::WriteToMessage(message);
  WriteToMessage(message->MutableExtension(serialization::Rotation::extension));
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::ReadFromMessage(
    serialization::LinearMap const& message) {
  LinearMap<FromFrame, ToFrame>::ReadFromMessage(message);
  CHECK(message.HasExtension(serialization::Rotation::extension));
  return ReadFromMessage(
      message.GetExtension(serialization::Rotation::extension));
}

template<typename FromFrame, typename ToFrame>
void Rotation<FromFrame, ToFrame>::WriteToMessage(
    not_null<serialization::Rotation*> const message) const {
  quaternion_.WriteToMessage(message->mutable_quaternion());
}

template<typename FromFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> Rotation<FromFrame, ToFrame>::ReadFromMessage(
    serialization::Rotation const& message) {
  return Rotation(Quaternion::ReadFromMessage(message.quaternion()));
}

template<typename FromFrame, typename ToFrame>
template<typename Scalar>
R3Element<Scalar> Rotation<FromFrame, ToFrame>::operator()(
    R3Element<Scalar> const& r3_element) const {
  double const real_part = quaternion_.real_part();
  R3Element<double> const& imaginary_part = quaternion_.imaginary_part();
  return r3_element + 2 * Cross(imaginary_part,
                                Cross(imaginary_part, r3_element) +
                                      real_part * r3_element);
}

template<typename FromFrame, typename ThroughFrame, typename ToFrame>
Rotation<FromFrame, ToFrame> operator*(
    Rotation<ThroughFrame, ToFrame> const& left,
    Rotation<FromFrame, ThroughFrame> const& right) {
  return Rotation<FromFrame, ToFrame>(left.quaternion_ * right.quaternion_);
}

template<typename FromFrame, typename ToFrame>
std::ostream& operator<<(std::ostream& out,
                         Rotation<FromFrame, ToFrame> const& rotation) {
  return out << rotation.quaternion_;
}

}  // namespace geometry
}  // namespace principia
<|endoftext|>


<commit_before><commit_msg>Pass a useful exception message.<commit_after><|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <chromaprint.h>
#include "audio/ffmpeg_audio_reader.h"
#include "utils/scope_exit.h"

using namespace chromaprint;

enum Format {
	TEXT = 0,
	JSON,
	PLAIN,
};

static Format g_format = TEXT;
static char *g_input_format = nullptr;
static int g_input_channels = 0;
static int g_input_sample_rate = 0;
static double g_max_duration = 120;
static double g_chunk_duration = 0;
static bool g_overlap = false;
static bool g_raw = false;

const char *g_help =
	"Usage: %s [OPTIONS] FILE [FILE...]\n"
	"\n"
	"Generate fingerprints from audio files/streams.\n"
	"\n"
	"Options:\n"
	"  -format NAME   Set the input format name\n"
	"  -rate NUM      Set the sample rate of the input audio\n"
	"  -channels NUM  Set the number of channels in the input audio\n"
	"  -length SECS   Restrict the duration of the processed input audio (default 120)\n"
	"  -chunk SECS    Split the input audio into chunks of this duration\n"
	"  -overlap       Overlap the chunks slightly to make sure audio on the edges is fingerprinted\n"
	"  -raw           Output fingerprints in the uncompressed format\n"
	"  -json          Print the output in JSON format\n"
	"  -text          Print the output in text format\n"
	"  -plain         Print the just the fingerprint in text format\n"
	;

static void ParseOptions(int &argc, char **argv) {
	int j = 1;
	for (int i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--")) {
			while (++i < argc) {
				argv[j++] = argv[i];
			}
		} else if ((!strcmp(argv[i], "-format") || !strcmp(argv[i], "-f")) && i + 1 < argc) {
			g_input_format = argv[++i];
		} else if ((!strcmp(argv[i], "-channels") || !strcmp(argv[i], "-c")) && i + 1 < argc) {
			auto value = atoi(argv[i + 1]);
			if (value > 0) {
				g_input_channels = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a non-zero positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if ((!strcmp(argv[i], "-rate") || !strcmp(argv[i], "-r")) && i + 1 < argc) {
			auto value = atoi(argv[i + 1]);
			if (value >= 0) {
				g_input_sample_rate = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if ((!strcmp(argv[i], "-length") || !strcmp(argv[i], "-t")) && i + 1 < argc) {
			auto value = atof(argv[i + 1]);
			if (value >= 0) {
				g_max_duration = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if (!strcmp(argv[i], "-chunk") && i + 1 < argc) {
			auto value = atof(argv[i + 1]);
			if (value >= 0) {
				g_chunk_duration = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if (!strcmp(argv[i], "-text")) {
			g_format = TEXT;
		} else if (!strcmp(argv[i], "-json")) {
			g_format = JSON;
		} else if (!strcmp(argv[i], "-plain")) {
			g_format = PLAIN;
		} else if (!strcmp(argv[i], "-overlap")) {
			g_overlap = true;
		} else if (!strcmp(argv[i], "-raw")) {
			g_raw = true;
		} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
			fprintf(stdout, g_help, argv[0]);
			exit(0);
		} else {
			const auto len = strlen(argv[i]);
			if (len > 1 && argv[i][0] == '-') {
				fprintf(stderr, "ERROR: Unknown option %s\n", argv[i]);
				exit(2);
			} else {
				argv[j++] = argv[i];
			}
		}
	}
	if (j < 2) {
		fprintf(stderr, "ERROR: No input files\n");
		exit(2);
	}
	argc = j;
}

void PrintResult(ChromaprintContext *ctx, FFmpegAudioReader &reader) {
	std::string tmp_fp;
	const char *fp;
	bool dealloc_fp = false;

	if (g_raw) {
		std::stringstream ss;
		uint32_t *raw_fp_data = nullptr;
		int raw_fp_size = 0;
		if (!chromaprint_get_raw_fingerprint(ctx, &raw_fp_data, &raw_fp_size)) {
			fprintf(stderr, "ERROR: Could not get the fingerprinting\n");
			exit(2);
		}
		SCOPE_EXIT(chromaprint_dealloc(raw_fp_data));
		for (int i = 0; i < raw_fp_size; i++) {
			if (i > 0) {
				ss << ',';
			}
			ss << int32_t(raw_fp_data[i]);
		}
		tmp_fp = ss.str();
		fp = tmp_fp.c_str();
	} else {
		char *tmp_fp2;
		if (!chromaprint_get_fingerprint(ctx, &tmp_fp2)) {
			fprintf(stderr, "ERROR: Could not get the fingerprinting\n");
			exit(2);
		}
		fp = tmp_fp2;
		dealloc_fp = true;
	}
	SCOPE_EXIT(if (dealloc_fp) { chromaprint_dealloc((void *) fp); });

	const auto duration = reader.GetDuration() / 1000.0;

	switch (g_format) {
		case TEXT:
			printf("DURATION=%.2f\nFINGERPRINT=%s\n", duration, fp);
			break;
		case JSON:
			if (g_raw) {
				printf("{\"duration\": %.2f, \"fingerprint\": [%s]}\n", duration, fp);
			} else {
				printf("{\"duration\": %.2f, \"fingerprint\": \"%s\"}\n", duration, fp);
			}
			break;
		case PLAIN:
			printf("%s\n", fp);
			break;
	}
}

void ProcessFile(ChromaprintContext *ctx, FFmpegAudioReader &reader, const char *file_name) {
	if (!reader.Open(file_name)) {
		fprintf(stderr, "ERROR: %s\n", reader.GetError().c_str());
		exit(2);
	}

	size_t remaining = g_max_duration * reader.GetSampleRate();

	if (!chromaprint_start(ctx, reader.GetSampleRate(), reader.GetChannels())) {
		fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
		exit(2);
	}

	size_t chunk = 0;
	const size_t chunk_limit = g_chunk_duration * reader.GetSampleRate();
	while (!reader.IsFinished()) {
		const int16_t *data = nullptr;
		size_t size = 0;
		if (!reader.Read(&data, &size)) {
			fprintf(stderr, "ERROR: %s\n", reader.GetError().c_str());
			exit(2);
		}

		if (data) {
			if (g_max_duration > 0) {
				if (size > remaining) {
					size = remaining;
				}
				remaining -= size;
			}

			size_t first_part_size = size;
			if (chunk_limit > 0 && chunk + size > chunk_limit) {
				first_part_size = chunk_limit - chunk;
			}

			if (!chromaprint_feed(ctx, data, first_part_size * reader.GetChannels())) {
				fprintf(stderr, "ERROR: Could not process audio data\n");
				exit(2);
			}

			data += first_part_size * reader.GetChannels();
			size -= first_part_size;

			chunk += first_part_size;

			if (chunk_limit > 0 && chunk >= chunk_limit) {
				if (!chromaprint_finish(ctx)) {
					fprintf(stderr, "ERROR: Could not finish the fingerprinting process\n");
					exit(2);
				}
				PrintResult(ctx, reader);
				if (g_overlap) {
					if (!chromaprint_clear_fingerprint(ctx)) {
						fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
						exit(2);
					}
				} else {
					if (!chromaprint_start(ctx, reader.GetSampleRate(), reader.GetChannels())) {
						fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
						exit(2);
					}
				}
				chunk -= chunk_limit;
			}

			if (size > 0) {
				if (!chromaprint_feed(ctx, data, size * reader.GetChannels())) {
					fprintf(stderr, "ERROR: Could not process audio data\n");
					exit(2);
				}
			}

			chunk += size;

			if (g_max_duration > 0 && remaining == 0) {
				break;
			}
		}
	}

	if (!chromaprint_finish(ctx)) {
		fprintf(stderr, "ERROR: Could not finish the fingerprinting process\n");
		exit(2);
	}

	if (chunk > 0) {
		PrintResult(ctx, reader);
	}
}

int main(int argc, char **argv) {
	ParseOptions(argc, argv);

	FFmpegAudioReader reader;
	if (g_input_format) {
		if (!reader.SetInputFormat(g_input_format)) {
			fprintf(stderr, "ERROR: Invalid format\n");
			return 2;
		}
	}
	if (g_input_channels) {
		if (!reader.SetInputChannels(g_input_channels)) {
			fprintf(stderr, "ERROR: Invalid number of channels\n");
			return 2;
		}
	}
	if (g_input_sample_rate) {
		if (!reader.SetInputSampleRate(g_input_sample_rate)) {
			fprintf(stderr, "ERROR: Invalid sample rate\n");
			return 2;
		}
	}

	ChromaprintContext *chromaprint_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
	SCOPE_EXIT(chromaprint_free(chromaprint_ctx));

	reader.SetOutputChannels(chromaprint_get_num_channels(chromaprint_ctx));
	reader.SetOutputSampleRate(chromaprint_get_sample_rate(chromaprint_ctx));

	for (int i = 1; i < argc; i++) {
		ProcessFile(chromaprint_ctx, reader, argv[i]);
	}

	return 0;
}
<commit_msg>Print unsigned ints from `fpcalc -raw`<commit_after>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <chromaprint.h>
#include "audio/ffmpeg_audio_reader.h"
#include "utils/scope_exit.h"

using namespace chromaprint;

enum Format {
	TEXT = 0,
	JSON,
	PLAIN,
};

static Format g_format = TEXT;
static char *g_input_format = nullptr;
static int g_input_channels = 0;
static int g_input_sample_rate = 0;
static double g_max_duration = 120;
static double g_chunk_duration = 0;
static bool g_overlap = false;
static bool g_raw = false;

const char *g_help =
	"Usage: %s [OPTIONS] FILE [FILE...]\n"
	"\n"
	"Generate fingerprints from audio files/streams.\n"
	"\n"
	"Options:\n"
	"  -format NAME   Set the input format name\n"
	"  -rate NUM      Set the sample rate of the input audio\n"
	"  -channels NUM  Set the number of channels in the input audio\n"
	"  -length SECS   Restrict the duration of the processed input audio (default 120)\n"
	"  -chunk SECS    Split the input audio into chunks of this duration\n"
	"  -overlap       Overlap the chunks slightly to make sure audio on the edges is fingerprinted\n"
	"  -raw           Output fingerprints in the uncompressed format\n"
	"  -json          Print the output in JSON format\n"
	"  -text          Print the output in text format\n"
	"  -plain         Print the just the fingerprint in text format\n"
	;

static void ParseOptions(int &argc, char **argv) {
	int j = 1;
	for (int i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--")) {
			while (++i < argc) {
				argv[j++] = argv[i];
			}
		} else if ((!strcmp(argv[i], "-format") || !strcmp(argv[i], "-f")) && i + 1 < argc) {
			g_input_format = argv[++i];
		} else if ((!strcmp(argv[i], "-channels") || !strcmp(argv[i], "-c")) && i + 1 < argc) {
			auto value = atoi(argv[i + 1]);
			if (value > 0) {
				g_input_channels = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a non-zero positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if ((!strcmp(argv[i], "-rate") || !strcmp(argv[i], "-r")) && i + 1 < argc) {
			auto value = atoi(argv[i + 1]);
			if (value >= 0) {
				g_input_sample_rate = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if ((!strcmp(argv[i], "-length") || !strcmp(argv[i], "-t")) && i + 1 < argc) {
			auto value = atof(argv[i + 1]);
			if (value >= 0) {
				g_max_duration = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if (!strcmp(argv[i], "-chunk") && i + 1 < argc) {
			auto value = atof(argv[i + 1]);
			if (value >= 0) {
				g_chunk_duration = value;
			} else {
				fprintf(stderr, "ERROR: The argument for %s must be a positive number\n", argv[i]);
				exit(2);
			}
			i++;
		} else if (!strcmp(argv[i], "-text")) {
			g_format = TEXT;
		} else if (!strcmp(argv[i], "-json")) {
			g_format = JSON;
		} else if (!strcmp(argv[i], "-plain")) {
			g_format = PLAIN;
		} else if (!strcmp(argv[i], "-overlap")) {
			g_overlap = true;
		} else if (!strcmp(argv[i], "-raw")) {
			g_raw = true;
		} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
			fprintf(stdout, g_help, argv[0]);
			exit(0);
		} else {
			const auto len = strlen(argv[i]);
			if (len > 1 && argv[i][0] == '-') {
				fprintf(stderr, "ERROR: Unknown option %s\n", argv[i]);
				exit(2);
			} else {
				argv[j++] = argv[i];
			}
		}
	}
	if (j < 2) {
		fprintf(stderr, "ERROR: No input files\n");
		exit(2);
	}
	argc = j;
}

void PrintResult(ChromaprintContext *ctx, FFmpegAudioReader &reader) {
	std::string tmp_fp;
	const char *fp;
	bool dealloc_fp = false;

	if (g_raw) {
		std::stringstream ss;
		uint32_t *raw_fp_data = nullptr;
		int raw_fp_size = 0;
		if (!chromaprint_get_raw_fingerprint(ctx, &raw_fp_data, &raw_fp_size)) {
			fprintf(stderr, "ERROR: Could not get the fingerprinting\n");
			exit(2);
		}
		SCOPE_EXIT(chromaprint_dealloc(raw_fp_data));
		for (int i = 0; i < raw_fp_size; i++) {
			if (i > 0) {
				ss << ',';
			}
			ss << raw_fp_data[i];
		}
		tmp_fp = ss.str();
		fp = tmp_fp.c_str();
	} else {
		char *tmp_fp2;
		if (!chromaprint_get_fingerprint(ctx, &tmp_fp2)) {
			fprintf(stderr, "ERROR: Could not get the fingerprinting\n");
			exit(2);
		}
		fp = tmp_fp2;
		dealloc_fp = true;
	}
	SCOPE_EXIT(if (dealloc_fp) { chromaprint_dealloc((void *) fp); });

	const auto duration = reader.GetDuration() / 1000.0;

	switch (g_format) {
		case TEXT:
			printf("DURATION=%.2f\nFINGERPRINT=%s\n", duration, fp);
			break;
		case JSON:
			if (g_raw) {
				printf("{\"duration\": %.2f, \"fingerprint\": [%s]}\n", duration, fp);
			} else {
				printf("{\"duration\": %.2f, \"fingerprint\": \"%s\"}\n", duration, fp);
			}
			break;
		case PLAIN:
			printf("%s\n", fp);
			break;
	}
}

void ProcessFile(ChromaprintContext *ctx, FFmpegAudioReader &reader, const char *file_name) {
	if (!reader.Open(file_name)) {
		fprintf(stderr, "ERROR: %s\n", reader.GetError().c_str());
		exit(2);
	}

	size_t remaining = g_max_duration * reader.GetSampleRate();

	if (!chromaprint_start(ctx, reader.GetSampleRate(), reader.GetChannels())) {
		fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
		exit(2);
	}

	size_t chunk = 0;
	const size_t chunk_limit = g_chunk_duration * reader.GetSampleRate();
	while (!reader.IsFinished()) {
		const int16_t *data = nullptr;
		size_t size = 0;
		if (!reader.Read(&data, &size)) {
			fprintf(stderr, "ERROR: %s\n", reader.GetError().c_str());
			exit(2);
		}

		if (data) {
			if (g_max_duration > 0) {
				if (size > remaining) {
					size = remaining;
				}
				remaining -= size;
			}

			size_t first_part_size = size;
			if (chunk_limit > 0 && chunk + size > chunk_limit) {
				first_part_size = chunk_limit - chunk;
			}

			if (!chromaprint_feed(ctx, data, first_part_size * reader.GetChannels())) {
				fprintf(stderr, "ERROR: Could not process audio data\n");
				exit(2);
			}

			data += first_part_size * reader.GetChannels();
			size -= first_part_size;

			chunk += first_part_size;

			if (chunk_limit > 0 && chunk >= chunk_limit) {
				if (!chromaprint_finish(ctx)) {
					fprintf(stderr, "ERROR: Could not finish the fingerprinting process\n");
					exit(2);
				}
				PrintResult(ctx, reader);
				if (g_overlap) {
					if (!chromaprint_clear_fingerprint(ctx)) {
						fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
						exit(2);
					}
				} else {
					if (!chromaprint_start(ctx, reader.GetSampleRate(), reader.GetChannels())) {
						fprintf(stderr, "ERROR: Could not initialize the fingerprinting process\n");
						exit(2);
					}
				}
				chunk -= chunk_limit;
			}

			if (size > 0) {
				if (!chromaprint_feed(ctx, data, size * reader.GetChannels())) {
					fprintf(stderr, "ERROR: Could not process audio data\n");
					exit(2);
				}
			}

			chunk += size;

			if (g_max_duration > 0 && remaining == 0) {
				break;
			}
		}
	}

	if (!chromaprint_finish(ctx)) {
		fprintf(stderr, "ERROR: Could not finish the fingerprinting process\n");
		exit(2);
	}

	if (chunk > 0) {
		PrintResult(ctx, reader);
	}
}

int main(int argc, char **argv) {
	ParseOptions(argc, argv);

	FFmpegAudioReader reader;
	if (g_input_format) {
		if (!reader.SetInputFormat(g_input_format)) {
			fprintf(stderr, "ERROR: Invalid format\n");
			return 2;
		}
	}
	if (g_input_channels) {
		if (!reader.SetInputChannels(g_input_channels)) {
			fprintf(stderr, "ERROR: Invalid number of channels\n");
			return 2;
		}
	}
	if (g_input_sample_rate) {
		if (!reader.SetInputSampleRate(g_input_sample_rate)) {
			fprintf(stderr, "ERROR: Invalid sample rate\n");
			return 2;
		}
	}

	ChromaprintContext *chromaprint_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
	SCOPE_EXIT(chromaprint_free(chromaprint_ctx));

	reader.SetOutputChannels(chromaprint_get_num_channels(chromaprint_ctx));
	reader.SetOutputSampleRate(chromaprint_get_sample_rate(chromaprint_ctx));

	for (int i = 1; i < argc; i++) {
		ProcessFile(chromaprint_ctx, reader, argv[i]);
	}

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>my previous fix triggered an assert in clang<commit_after><|endoftext|>


<commit_before>/**
 * \file XTPlot.cpp
 * \brief Implements class for drawing the XT plots
 */

#include "XTPlot.h"
#include "ChaosSettings.h"

XTPlot::XTPlot(wxWindow* parent, wxWindowID id, const wxPoint& pos,
                       const wxSize& size, long style, const wxString& name)
                       : ChaosPlot(parent, id, pos, size, style, name) {
    /**
    *   Constructor for the XT plot. Defaults to only showing X.
    */
    side_gutter_size = 20;
    bottom_gutter_size = 20;
    x1Visible = true;
    x2Visible = false;
    x3Visible = false;
    graph_title = wxT("Waveform as a function of time");
    graph_subtitle = wxT("X (V) vs. T");
}

XTPlot::~XTPlot() {
    /**
    *   Deconstructor for the Rotating3dPlot class
    */
}

void XTPlot::drawPlot() {
    /**
    *   Main drawing function for the XTPlot class.
    *
    *   Calculates the units for the axis and then draws them
    *   Draws an XT graph using X, X', and X'' depending on which ones
    *   the user has selected.
    *
    */
    const int xt_points = 300;

    static int times_called = 0;

    int x1,x2,x1_old,x2_old, x3, x3_old;
    int start;

    startDraw();
    if(ChaosSettings::YAxisLabels == ChaosSettings::Y_AXIS_VGND) {
        graph_subtitle = wxT("X (V) vs. T");
        drawYAxis(0.0,3.3,1);
    } else if(ChaosSettings::YAxisLabels == ChaosSettings::Y_AXIS_VBIAS) {
        graph_subtitle = wxT("X (V) vs. T");
        drawYAxis(-1.2,2.1,.5);
    } else {
        graph_subtitle = wxT("X (ADC) vs. T");
        drawYAxis(0,1024,341);
    }
    drawXAxis(0,5,1);

    if(device_connected == false) {
        endDraw();
        return;
    }

    int plot_width = width-side_gutter_size-2;
    int plot_points;
    float x_scale;
    float y_scale = float(graph_height)/1024.0;

    plot_points = xt_points;
    x_scale = float(plot_width)/xt_points;

    start = libchaos_getTriggerIndex();

    // Get first plot point
    libchaos_getPlotPoint(&x1,&x2,&x3, start);
    x3 = graph_height + top_gutter_size - int(x3*y_scale);
    x2 = graph_height + top_gutter_size - int(x2*y_scale);
    x1 = graph_height + top_gutter_size - int(x1*y_scale);
    x1_old = x1;
    x2_old = x2;
    x3_old = x3;

    for(int i = 1; i < plot_points; i++) {
        libchaos_getPlotPoint(&x1,&x2,&x3, i+start);
        x3 = graph_height + top_gutter_size - int(x3*y_scale);
        x2 = graph_height + top_gutter_size - int(x2*y_scale);
        x1 = graph_height + top_gutter_size - int(x1*y_scale);

        if(x1Visible == true) {
            //Use red pen
            wxPen rPen(*wxRED, 2); // red pen of width 2
            buffer->SetPen(rPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x1_old, (int)(x_scale*i+side_gutter_size+1), x1);
        }

        if(x2Visible == true) {
            //Use blue pen
            wxPen bPen(*wxBLUE, 2); // blue pen of width 2
            buffer->SetPen(bPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x2_old, (int)(x_scale*i+side_gutter_size+1), x2);
        }

        if(x3Visible == true) {
            //Use green pen
            wxPen gPen(*wxGREEN, 2); // blue pen of width 2
            buffer->SetPen(gPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x3_old, (int)(x_scale*i+side_gutter_size+1), x3);
        }

        x1_old = x1;
        x2_old = x2;
        x3_old = x3;
    }
    times_called = 0;

    // Display buffer
    endDraw();
}

void XTPlot::setX1Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X on the graph
    */
    x1Visible = visible;
}

void XTPlot::setX2Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X' on the graph
    */
    x2Visible = visible;
}

void XTPlot::setX3Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X'' on the graph
    */
    x3Visible = visible;
}
<commit_msg>- added time graph to XT plot<commit_after>/**
 * \file XTPlot.cpp
 * \brief Implements class for drawing the XT plots
 */

#include "XTPlot.h"
#include "ChaosSettings.h"

XTPlot::XTPlot(wxWindow* parent, wxWindowID id, const wxPoint& pos,
                       const wxSize& size, long style, const wxString& name)
                       : ChaosPlot(parent, id, pos, size, style, name) {
    /**
    *   Constructor for the XT plot. Defaults to only showing X.
    */
    side_gutter_size = 20;
    bottom_gutter_size = 20;
    x1Visible = true;
    x2Visible = false;
    x3Visible = false;
    graph_title = wxT("Waveform as a function of time");
    graph_subtitle = wxT("X (V) vs. T(ms)");
}

XTPlot::~XTPlot() {
    /**
    *   Deconstructor for the Rotating3dPlot class
    */
}

void XTPlot::drawPlot() {
    /**
    *   Main drawing function for the XTPlot class.
    *
    *   Calculates the units for the axis and then draws them
    *   Draws an XT graph using X, X', and X'' depending on which ones
    *   the user has selected.
    *
    */
    const int xt_points = 300;

    // max time on the graph in ms
    float max_time = xt_points*(1/72000.0)*1000;

    static int times_called = 0;

    int x1,x2,x1_old,x2_old, x3, x3_old;
    int start;

    startDraw();
    if(ChaosSettings::YAxisLabels == ChaosSettings::Y_AXIS_VGND) {
        graph_subtitle = wxT("X (V) vs. T(ms)");
        drawYAxis(0.0,3.3,1);
    } else if(ChaosSettings::YAxisLabels == ChaosSettings::Y_AXIS_VBIAS) {
        graph_subtitle = wxT("X (V) vs. T(ms)");
        drawYAxis(-1.2,2.1,.5);
    } else {
        graph_subtitle = wxT("X (ADC) vs. T(ms)");
        drawYAxis(0,1024,341);
    }
    drawXAxis(0,max_time,max_time/5.0);

    if(device_connected == false) {
        endDraw();
        return;
    }

    int plot_width = width-side_gutter_size-2;
    int plot_points;
    float x_scale;
    float y_scale = float(graph_height)/1024.0;

    plot_points = xt_points;
    x_scale = float(plot_width)/xt_points;

    start = libchaos_getTriggerIndex();

    // Get first plot point
    libchaos_getPlotPoint(&x1,&x2,&x3, start);
    x3 = graph_height + top_gutter_size - int(x3*y_scale);
    x2 = graph_height + top_gutter_size - int(x2*y_scale);
    x1 = graph_height + top_gutter_size - int(x1*y_scale);
    x1_old = x1;
    x2_old = x2;
    x3_old = x3;

    for(int i = 1; i < plot_points; i++) {
        libchaos_getPlotPoint(&x1,&x2,&x3, i+start);
        x3 = graph_height + top_gutter_size - int(x3*y_scale);
        x2 = graph_height + top_gutter_size - int(x2*y_scale);
        x1 = graph_height + top_gutter_size - int(x1*y_scale);

        if(x1Visible == true) {
            //Use red pen
            wxPen rPen(*wxRED, 2); // red pen of width 2
            buffer->SetPen(rPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x1_old, (int)(x_scale*i+side_gutter_size+1), x1);
        }

        if(x2Visible == true) {
            //Use blue pen
            wxPen bPen(*wxBLUE, 2); // blue pen of width 2
            buffer->SetPen(bPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x2_old, (int)(x_scale*i+side_gutter_size+1), x2);
        }

        if(x3Visible == true) {
            //Use green pen
            wxPen gPen(*wxGREEN, 2); // blue pen of width 2
            buffer->SetPen(gPen);
            buffer->DrawLine((int)(x_scale*(i-1)+side_gutter_size+1), x3_old, (int)(x_scale*i+side_gutter_size+1), x3);
        }

        x1_old = x1;
        x2_old = x2;
        x3_old = x3;
    }
    times_called = 0;

    // Display buffer
    endDraw();
}

void XTPlot::setX1Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X on the graph
    */
    x1Visible = visible;
}

void XTPlot::setX2Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X' on the graph
    */
    x2Visible = visible;
}

void XTPlot::setX3Visibility(bool visible) {
    /**
    *   Enables or disables the visibility of X'' on the graph
    */
    x3Visible = visible;
}
<|endoftext|>


<commit_before>#include "catch.hpp"

#include <shadow.hpp>

class tct1_class
{
public:
    tct1_class() = default;

    tct1_class(int i) : i_(i)
    {
    }

    int
    get_i() const
    {
        return i_;
    }

private:
    int i_;
};

int
extract_i(const tct1_class& a)
{
    return a.get_i();
}

namespace tct1_space
{
REGISTER_TYPE_BEGIN()
REGISTER_TYPE(tct1_class)
REGISTER_TYPE_END()

REGISTER_CONSTRUCTOR(tct1_class)

REGISTER_FREE_FUNCTION(extract_i)

SHADOW_INIT()
}

namespace tct1_space2
{
REGISTER_TYPE_BEGIN()
REGISTER_TYPE(tct1_class)
REGISTER_TYPE_END()

REGISTER_CONSTRUCTOR(tct1_class, int)

REGISTER_MEMBER_FUNCTION(tct1_class, get_i)

SHADOW_INIT()
}

TEST_CASE("create an int using static_construct", "[static_construct]")
{
    auto anint = tct1_space::static_construct<int>(23);

    REQUIRE(anint.type().name() == std::string("int"));
    REQUIRE(tct1_space::get_held_value<int>(anint) == 23);

    SECTION(
        "find constructor for tct1_class from tct1_space2 namespace manager")
    {
        auto constructors = tct1_space2::manager.constructors();

        auto found = std::find_if(
            constructors.first, constructors.second, [](const auto& ct) {
                const auto name =
                    tct1_space2::manager.constructor_type(ct).name();

                return name == std::string("tct1_class");
            });

        auto paramtypes =
            tct1_space2::manager.constructor_parameter_types(*found);

        REQUIRE(found != constructors.second);
        REQUIRE(std::distance(paramtypes.first, paramtypes.second) == 1);
        REQUIRE(paramtypes.first->name() == std::string("int"));

        SECTION("construct a tct1_class from tct1_space2 with int from "
                "tct1_space namespace")
        {
            std::vector<shadow::object> args{anint};

            auto res = tct1_space2::manager.construct_object(
                *found, args.begin(), args.end());

            REQUIRE(res.type().name() == std::string("tct1_class"));
            REQUIRE(tct1_space2::get_held_value<tct1_class>(res).get_i() == 23);
            REQUIRE(tct1_space::get_held_value<tct1_class>(res).get_i() == 23);

            SECTION("find all free functions from tct1_space")
            {
                auto ffs = tct1_space::manager.free_functions();

                REQUIRE(std::distance(ffs.first, ffs.second) > 0);

                SECTION("find free function taking tct1_class as argument")
                {
                    auto ff_found =
                        std::find_if(ffs.first, ffs.second, [](const auto& ff) {

                            auto param_types =
                                tct1_space::manager
                                    .free_function_parameter_types(ff);

                            return (std::distance(param_types.first,
                                                  param_types.second) == 1) &&
                                   (param_types.first->name() ==
                                    std::string("tct1_class"));

                        });

                    REQUIRE(ff_found != ffs.second);

                    SECTION("call free function")
                    {
                        auto ff_res = tct1_space::manager.call_free_function(
                            *ff_found, &res, &res + 1);

                        REQUIRE(ff_res.type().name() == std::string("int"));
                        REQUIRE(tct1_space::get_held_value<int>(ff_res) == 23);
                    }
                }
            }
        }
    }

    SECTION("find all type conversions available")
    {
        auto conversions = tct1_space::manager.conversions();

        SECTION("find conversion from int to float")
        {
            auto found = std::find_if(
                conversions.first, conversions.second, [](const auto& cv) {
                    auto conv_types = tct1_space::manager.conversion_types(cv);

                    return conv_types.first.name() == std::string("int") &&
                           conv_types.second.name() == std::string("float");
                });

            REQUIRE(found != conversions.second);

            SECTION("convert int to float")
            {
                auto res = tct1_space::manager.convert(*found, anint);

                REQUIRE(res.type().name() == std::string("float"));
                REQUIRE(tct1_space::get_held_value<float>(res) ==
                        Approx(23.0f));
            }
        }
    }
}
<commit_msg>Add unit tests for different parameter types. 	modified:   tests/test_compile_time1.cpp<commit_after>#include "catch.hpp"

#include <shadow.hpp>

class tct1_class
{
public:
    tct1_class() = default;

    tct1_class(int i) : i_(i)
    {
    }

    int
    get_i() const
    {
        return i_;
    }

private:
    int i_;
};

int
extract_i(const tct1_class& a)
{
    return a.get_i();
}

int
mult(const int* i)
{
    return *i * 2;
}

void
modify(int* i)
{
    *i += 10;
}

void
triple(int& i)
{
    i *= 3;
}

namespace tct1_space
{
REGISTER_TYPE_BEGIN()
REGISTER_TYPE(tct1_class)
REGISTER_TYPE_END()

REGISTER_CONSTRUCTOR(tct1_class)

REGISTER_FREE_FUNCTION(extract_i)

SHADOW_INIT()
}

namespace tct1_space2
{
REGISTER_TYPE_BEGIN()
REGISTER_TYPE(tct1_class)
REGISTER_TYPE_END()

REGISTER_CONSTRUCTOR(tct1_class, int)

REGISTER_MEMBER_FUNCTION(tct1_class, get_i)

REGISTER_FREE_FUNCTION(mult)
REGISTER_FREE_FUNCTION(modify)
REGISTER_FREE_FUNCTION(triple)

SHADOW_INIT()
}

TEST_CASE("create an int using static_construct", "[static_construct]")
{
    auto anint = tct1_space::static_construct<int>(23);
    auto anint2 = tct1_space2::static_construct<int>(100);

    REQUIRE(anint.type().name() == std::string("int"));
    REQUIRE(tct1_space::get_held_value<int>(anint) == 23);

    SECTION(
        "find constructor for tct1_class from tct1_space2 namespace manager")
    {
        auto constructors = tct1_space2::manager.constructors();

        auto found = std::find_if(
            constructors.first, constructors.second, [](const auto& ct) {
                const auto name =
                    tct1_space2::manager.constructor_type(ct).name();

                return name == std::string("tct1_class");
            });

        auto paramtypes =
            tct1_space2::manager.constructor_parameter_types(*found);

        REQUIRE(found != constructors.second);
        REQUIRE(std::distance(paramtypes.first, paramtypes.second) == 1);
        REQUIRE(paramtypes.first->name() == std::string("int"));

        SECTION("construct a tct1_class from tct1_space2 with int from "
                "tct1_space namespace")
        {
            std::vector<shadow::object> args{anint};

            auto res = tct1_space2::manager.construct_object(
                *found, args.begin(), args.end());

            REQUIRE(res.type().name() == std::string("tct1_class"));
            REQUIRE(tct1_space2::get_held_value<tct1_class>(res).get_i() == 23);
            REQUIRE(tct1_space::get_held_value<tct1_class>(res).get_i() == 23);

            SECTION("find all free functions from tct1_space")
            {
                auto ffs = tct1_space::manager.free_functions();

                REQUIRE(std::distance(ffs.first, ffs.second) > 0);

                SECTION("find free function taking tct1_class as argument")
                {
                    auto ff_found =
                        std::find_if(ffs.first, ffs.second, [](const auto& ff) {

                            auto param_types =
                                tct1_space::manager
                                    .free_function_parameter_types(ff);

                            return (std::distance(param_types.first,
                                                  param_types.second) == 1) &&
                                   (param_types.first->name() ==
                                    std::string("tct1_class"));

                        });

                    REQUIRE(ff_found != ffs.second);

                    SECTION("call free function")
                    {
                        auto ff_res = tct1_space::manager.call_free_function(
                            *ff_found, &res, &res + 1);

                        REQUIRE(ff_res.type().name() == std::string("int"));
                        REQUIRE(tct1_space::get_held_value<int>(ff_res) == 23);
                    }
                }
            }
        }
    }

    SECTION("find all type conversions available")
    {
        auto conversions = tct1_space::manager.conversions();

        SECTION("find conversion from int to float")
        {
            auto found = std::find_if(
                conversions.first, conversions.second, [](const auto& cv) {
                    auto conv_types = tct1_space::manager.conversion_types(cv);

                    return conv_types.first.name() == std::string("int") &&
                           conv_types.second.name() == std::string("float");
                });

            REQUIRE(found != conversions.second);

            SECTION("convert int to float")
            {
                auto res = tct1_space::manager.convert(*found, anint);

                REQUIRE(res.type().name() == std::string("float"));
                REQUIRE(tct1_space::get_held_value<float>(res) ==
                        Approx(23.0f));
            }
        }
    }

    SECTION("find all functions from tct1_space2")
    {
        auto ffs = tct1_space2::manager.free_functions();

        REQUIRE(std::distance(ffs.first, ffs.second) == 3);

        SECTION("find function 'mult'")
        {
            auto found =
                std::find_if(ffs.first, ffs.second, [](const auto& ff) {
                    return tct1_space2::manager.free_function_name(ff) ==
                           std::string("mult");
                });

            REQUIRE(found != ffs.second);

            SECTION("call mult with anint2")
            {
                auto res = tct1_space2::manager.call_free_function(
                    *found, &anint2, &anint2 + 1);

                REQUIRE(res.type().name() == std::string("int"));
                REQUIRE(tct1_space2::get_held_value<int>(res) == 200);
                REQUIRE(tct1_space2::get_held_value<int>(anint2) == 100);
            }
        }

        SECTION("fund function 'modify'")
        {
            auto found =
                std::find_if(ffs.first, ffs.second, [](const auto& ff) {
                    return tct1_space2::manager.free_function_name(ff) ==
                           std::string("modify");
                });

            REQUIRE(found != ffs.second);

            SECTION("call mult with anint2")
            {
                auto res = tct1_space2::manager.call_free_function(
                    *found, &anint2, &anint2 + 1);

                REQUIRE(res.type().name() == std::string("void"));
                REQUIRE(tct1_space2::get_held_value<int>(anint2) == 110);
            }

            SECTION("call mult with anint1 in a vector")
            {
                std::vector<shadow::object> args{anint};

                auto res = tct1_space2::manager.call_free_function(
                    *found, args.begin(), args.end());

                REQUIRE(res.type().name() == std::string("void"));
                REQUIRE(tct1_space2::get_held_value<int>(args[0]) == 33);
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * 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 "atomic.h"

#include <pthread.h>
#include <vector>

#include "mutex.h"
#include "stl_util.h"
#include "stringprintf.h"

#if defined(__APPLE__)
#include <libkern/OSAtomic.h>
#endif
#if defined(__arm__)
#include <machine/cpu-features.h>
#endif

namespace art {

#if defined(HAVE_MACOSX_IPC)
#define NEED_MAC_QUASI_ATOMICS 1

#elif defined(__i386__) || defined(__x86_64__)
#define NEED_PTHREADS_QUASI_ATOMICS 1

#elif defined(__mips__)
#define NEED_PTHREADS_QUASI_ATOMICS 1

#elif defined(__arm__)

#if defined(__ARM_HAVE_LDREXD)
#define NEED_ARM_LDREXD_QUASI_ATOMICS 1
#else
#define NEED_PTHREADS_QUASI_ATOMICS 1
#endif

#elif defined(__sh__)
#define NEED_PTHREADS_QUASI_ATOMICS 1

#else
#error "QuasiAtomic unsupported on this platform"
#endif

// *****************************************************************************

#if NEED_ARM_LDREXD_QUASI_ATOMICS

static inline int64_t QuasiAtomicSwap64Impl(int64_t new_value, volatile int64_t* addr) {
  int64_t prev;
  int status;
  do {
    __asm__ __volatile__("@ QuasiAtomic::Swap64\n"
        "ldrexd     %0, %H0, [%3]\n"
        "strexd     %1, %4, %H4, [%3]"
        : "=&r" (prev), "=&r" (status), "+m"(*addr)
        : "r" (addr), "r" (new_value)
        : "cc");
  } while (__builtin_expect(status != 0, 0));
  return prev;
}

int64_t QuasiAtomic::Swap64(int64_t new_value, volatile int64_t* addr) {
  return QuasiAtomicSwap64Impl(new_value, addr);
}

int64_t QuasiAtomic::Swap64Sync(int64_t new_value, volatile int64_t* addr) {
  ANDROID_MEMBAR_STORE();
  int64_t old_value = QuasiAtomicSwap64Impl(new_value, addr);
  ANDROID_MEMBAR_FULL();
  return old_value;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  int64_t value;
  __asm__ __volatile__("@ QuasiAtomic::Read64\n"
      "ldrexd     %0, %H0, [%1]"
      : "=&r" (value)
      : "r" (addr));
  return value;
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  int64_t prev;
  int status;
  do {
    __asm__ __volatile__("@ QuasiAtomic::Cas64\n"
        "ldrexd     %0, %H0, [%3]\n"
        "mov        %1, #0\n"
        "teq        %0, %4\n"
        "teqeq      %H0, %H4\n"
        "strexdeq   %1, %5, %H5, [%3]"
        : "=&r" (prev), "=&r" (status), "+m"(*addr)
        : "r" (addr), "Ir" (old_value), "r" (new_value)
        : "cc");
  } while (__builtin_expect(status != 0, 0));
  return prev != old_value;
}

#endif

// *****************************************************************************

#if NEED_MAC_QUASI_ATOMICS

static inline int64_t QuasiAtomicSwap64Impl(int64_t value, volatile int64_t* addr) {
  int64_t old_value;
  do {
    old_value = *addr;
  } while (QuasiAtomic::Cas64(old_value, value, addr));
  return old_value;
}

int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
  return QuasiAtomicSwap64Impl(value, addr);
}

int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
  ANDROID_MEMBAR_STORE();
  int64_t old_value = QuasiAtomicSwap64Impl(value, addr);
  // TUNING: barriers can be avoided on some architectures.
  ANDROID_MEMBAR_FULL();
  return old_value;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  return OSAtomicAdd64Barrier(0, const_cast<volatile int64_t*>(addr));
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  return OSAtomicCompareAndSwap64Barrier(old_value, new_value, const_cast<int64_t*>(addr)) == 0;
}

#endif

// *****************************************************************************

#if NEED_PTHREADS_QUASI_ATOMICS

// In the absence of a better implementation, we implement the 64-bit atomic
// operations through mutex locking.

// We stripe across a bunch of different mutexes to reduce contention.
static const size_t kSwapLockCount = 32;
static std::vector<Mutex*>* gSwapLocks;

void QuasiAtomic::Startup() {
  gSwapLocks = new std::vector<Mutex*>;
  for (size_t i = 0; i < kSwapLockCount; ++i) {
    gSwapLocks->push_back(new Mutex(StringPrintf("QuasiAtomic stripe %d", i).c_str()));
  }
}

void QuasiAtomic::Shutdown() {
  STLDeleteElements(gSwapLocks);
  delete gSwapLocks;
}

static inline Mutex& GetSwapLock(const volatile int64_t* addr) {
  return *(*gSwapLocks)[((unsigned)(void*)(addr) >> 3U) % kSwapLockCount];
}

int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  int64_t old_value = *addr;
  *addr = value;
  return old_value;
}

int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
  // Same as QuasiAtomicSwap64 - mutex handles barrier.
  return QuasiAtomic::Swap64(value, addr);
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  if (*addr == old_value) {
    *addr  = new_value;
    return 0;
  }
  return 1;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  return *addr;
}

#else

// The other implementations don't need any special setup.
void QuasiAtomic::Startup() {}
void QuasiAtomic::Shutdown() {}

#endif

}  // namespace art
<commit_msg>Remove __sh__ from atomic.cc<commit_after>/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * 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 "atomic.h"

#include <pthread.h>
#include <vector>

#include "mutex.h"
#include "stl_util.h"
#include "stringprintf.h"

#if defined(__APPLE__)
#include <libkern/OSAtomic.h>
#endif
#if defined(__arm__)
#include <machine/cpu-features.h>
#endif

namespace art {

#if defined(HAVE_MACOSX_IPC)
#define NEED_MAC_QUASI_ATOMICS 1

#elif defined(__i386__) || defined(__x86_64__)
#define NEED_PTHREADS_QUASI_ATOMICS 1

#elif defined(__mips__)
#define NEED_PTHREADS_QUASI_ATOMICS 1

#elif defined(__arm__)

#if defined(__ARM_HAVE_LDREXD)
#define NEED_ARM_LDREXD_QUASI_ATOMICS 1
#else
#define NEED_PTHREADS_QUASI_ATOMICS 1
#endif

#else
#error "QuasiAtomic unsupported on this platform"
#endif

// *****************************************************************************

#if NEED_ARM_LDREXD_QUASI_ATOMICS

static inline int64_t QuasiAtomicSwap64Impl(int64_t new_value, volatile int64_t* addr) {
  int64_t prev;
  int status;
  do {
    __asm__ __volatile__("@ QuasiAtomic::Swap64\n"
        "ldrexd     %0, %H0, [%3]\n"
        "strexd     %1, %4, %H4, [%3]"
        : "=&r" (prev), "=&r" (status), "+m"(*addr)
        : "r" (addr), "r" (new_value)
        : "cc");
  } while (__builtin_expect(status != 0, 0));
  return prev;
}

int64_t QuasiAtomic::Swap64(int64_t new_value, volatile int64_t* addr) {
  return QuasiAtomicSwap64Impl(new_value, addr);
}

int64_t QuasiAtomic::Swap64Sync(int64_t new_value, volatile int64_t* addr) {
  ANDROID_MEMBAR_STORE();
  int64_t old_value = QuasiAtomicSwap64Impl(new_value, addr);
  ANDROID_MEMBAR_FULL();
  return old_value;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  int64_t value;
  __asm__ __volatile__("@ QuasiAtomic::Read64\n"
      "ldrexd     %0, %H0, [%1]"
      : "=&r" (value)
      : "r" (addr));
  return value;
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  int64_t prev;
  int status;
  do {
    __asm__ __volatile__("@ QuasiAtomic::Cas64\n"
        "ldrexd     %0, %H0, [%3]\n"
        "mov        %1, #0\n"
        "teq        %0, %4\n"
        "teqeq      %H0, %H4\n"
        "strexdeq   %1, %5, %H5, [%3]"
        : "=&r" (prev), "=&r" (status), "+m"(*addr)
        : "r" (addr), "Ir" (old_value), "r" (new_value)
        : "cc");
  } while (__builtin_expect(status != 0, 0));
  return prev != old_value;
}

#endif

// *****************************************************************************

#if NEED_MAC_QUASI_ATOMICS

static inline int64_t QuasiAtomicSwap64Impl(int64_t value, volatile int64_t* addr) {
  int64_t old_value;
  do {
    old_value = *addr;
  } while (QuasiAtomic::Cas64(old_value, value, addr));
  return old_value;
}

int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
  return QuasiAtomicSwap64Impl(value, addr);
}

int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
  ANDROID_MEMBAR_STORE();
  int64_t old_value = QuasiAtomicSwap64Impl(value, addr);
  // TUNING: barriers can be avoided on some architectures.
  ANDROID_MEMBAR_FULL();
  return old_value;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  return OSAtomicAdd64Barrier(0, const_cast<volatile int64_t*>(addr));
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  return OSAtomicCompareAndSwap64Barrier(old_value, new_value, const_cast<int64_t*>(addr)) == 0;
}

#endif

// *****************************************************************************

#if NEED_PTHREADS_QUASI_ATOMICS

// In the absence of a better implementation, we implement the 64-bit atomic
// operations through mutex locking.

// We stripe across a bunch of different mutexes to reduce contention.
static const size_t kSwapLockCount = 32;
static std::vector<Mutex*>* gSwapLocks;

void QuasiAtomic::Startup() {
  gSwapLocks = new std::vector<Mutex*>;
  for (size_t i = 0; i < kSwapLockCount; ++i) {
    gSwapLocks->push_back(new Mutex(StringPrintf("QuasiAtomic stripe %d", i).c_str()));
  }
}

void QuasiAtomic::Shutdown() {
  STLDeleteElements(gSwapLocks);
  delete gSwapLocks;
}

static inline Mutex& GetSwapLock(const volatile int64_t* addr) {
  return *(*gSwapLocks)[((unsigned)(void*)(addr) >> 3U) % kSwapLockCount];
}

int64_t QuasiAtomic::Swap64(int64_t value, volatile int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  int64_t old_value = *addr;
  *addr = value;
  return old_value;
}

int64_t QuasiAtomic::Swap64Sync(int64_t value, volatile int64_t* addr) {
  // Same as QuasiAtomicSwap64 - mutex handles barrier.
  return QuasiAtomic::Swap64(value, addr);
}

int QuasiAtomic::Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  if (*addr == old_value) {
    *addr  = new_value;
    return 0;
  }
  return 1;
}

int64_t QuasiAtomic::Read64(volatile const int64_t* addr) {
  MutexLock mu(GetSwapLock(addr));
  return *addr;
}

#else

// The other implementations don't need any special setup.
void QuasiAtomic::Startup() {}
void QuasiAtomic::Shutdown() {}

#endif

}  // namespace art
<|endoftext|>


<commit_before>//
//  utils.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/24/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include <stdio.h>

#include "pthread.h"

#include "utils.h"

bool qmtx_inited = false;
pthread_mutex_t qmtx;

std::string repr_string(const std::string &string)
{
	const char *p = string.c_str();
	const char *p_end = p + string.size();
	std::string ret;
	char buff[4];

	ret += "'";
	while (p != p_end) {
		char c = *p++;
		if (c == 10) {
			ret += "\\n";
		} else if (c == 13) {
			ret += "\\n";
		} else if (c >= ' ' && c <= '~') {
			sprintf(buff, "%c", c);
			ret += buff;
		} else {
			sprintf(buff, "\\x%02x", c & 0xff);
			ret += buff;
		}
	}
	return ret;
}

void log(void *obj, const char *format, ...)
{
	if (!qmtx_inited) {
		pthread_mutex_init(&qmtx, 0);
		qmtx_inited = true;
	}

	pthread_mutex_lock(&qmtx);

	FILE * file = stderr;
	fprintf(file, "tid(0x%lx): 0x%lx - ", (unsigned long)pthread_self(), (unsigned long)obj);
	va_list argptr;
	va_start(argptr, format);
	vfprintf(file, format, argptr);
	va_end(argptr);

	pthread_mutex_unlock(&qmtx);
}
<commit_msg>Fixed string repr<commit_after>//
//  utils.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/24/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include <stdio.h>

#include "pthread.h"

#include "utils.h"

bool qmtx_inited = false;
pthread_mutex_t qmtx;

std::string repr_string(const std::string &string)
{
	const char *p = string.c_str();
	const char *p_end = p + string.size();
	std::string ret;
	char buff[4];

	ret += "'";
	while (p != p_end) {
		char c = *p++;
		if (c == 10) {
			ret += "\\n";
		} else if (c == 13) {
			ret += "\\n";
		} else if (c >= ' ' && c <= '~') {
			sprintf(buff, "%c", c);
			ret += buff;
		} else {
			sprintf(buff, "\\x%02x", c & 0xff);
			ret += buff;
		}
	}
	ret += "'";
	return ret;
}

void log(void *obj, const char *format, ...)
{
	if (!qmtx_inited) {
		pthread_mutex_init(&qmtx, 0);
		qmtx_inited = true;
	}

	pthread_mutex_lock(&qmtx);

	FILE * file = stderr;
	fprintf(file, "tid(0x%lx): 0x%lx - ", (unsigned long)pthread_self(), (unsigned long)obj);
	va_list argptr;
	va_start(argptr, format);
	vfprintf(file, format, argptr);
	va_end(argptr);

	pthread_mutex_unlock(&qmtx);
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/cpu/lzx.h"

#include <algorithm>
#include <climits>

#include "xenia/base/byte_order.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
#include "xenia/kernel/util/xex2_info.h"

#include "third_party/mspack/lzx.h"
#include "third_party/mspack/mspack.h"

typedef struct mspack_memory_file_t {
  struct mspack_system sys;
  void* buffer;
  off_t buffer_size;
  off_t offset;
} mspack_memory_file;
mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer,
                                       const size_t buffer_size) {
  assert_true(buffer_size < INT_MAX);
  if (buffer_size >= INT_MAX) {
    return NULL;
  }
  mspack_memory_file* memfile =
      (mspack_memory_file*)calloc(1, sizeof(mspack_memory_file));
  if (!memfile) {
    return NULL;
  }
  memfile->buffer = buffer;
  memfile->buffer_size = (off_t)buffer_size;
  memfile->offset = 0;
  return memfile;
}
void mspack_memory_close(mspack_memory_file* file) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  free(memfile);
}
int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  const off_t remaining = memfile->buffer_size - memfile->offset;
  const off_t total = std::min(static_cast<off_t>(chars), remaining);
  std::memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total);
  memfile->offset += total;
  return (int)total;
}
int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  const off_t remaining = memfile->buffer_size - memfile->offset;
  const off_t total = std::min(static_cast<off_t>(chars), remaining);
  std::memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total);
  memfile->offset += total;
  return (int)total;
}
void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) {
  return std::calloc(chars, 1);
}
void mspack_memory_free(void* ptr) { free(ptr); }
void mspack_memory_copy(void* src, void* dest, size_t chars) {
  std::memcpy(dest, src, chars);
}
struct mspack_system* mspack_memory_sys_create() {
  struct mspack_system* sys =
      (struct mspack_system*)std::calloc(1, sizeof(struct mspack_system));
  if (!sys) {
    return NULL;
  }
  sys->read = mspack_memory_read;
  sys->write = mspack_memory_write;
  sys->alloc = mspack_memory_alloc;
  sys->free = mspack_memory_free;
  sys->copy = mspack_memory_copy;
  return sys;
}
void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); }

int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
                   size_t dest_len, uint32_t window_size, void* window_data,
                   size_t window_data_len) {
  uint32_t window_bits = 0;
  uint32_t temp_sz = window_size;
  for (size_t m = 0; m < 32; m++, window_bits++) {
    temp_sz >>= 1;
    if (temp_sz == 0x00000000) {
      break;
    }
  }

  int result_code = 1;

  mspack_system* sys = mspack_memory_sys_create();
  mspack_memory_file* lzxsrc =
      mspack_memory_open(sys, (void*)lzx_data, lzx_len);
  mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len);
  lzxd_stream* lzxd =
      lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst,
                window_bits, 0, 0x8000, (off_t)dest_len, 0);

  if (lzxd) {
    if (window_data) {
      // zero the window and then copy window_data to the end of it
      std::memset(lzxd->window, 0, window_data_len);
      std::memcpy(lzxd->window + (window_size - window_data_len), window_data,
                  window_data_len);
      lzxd->ref_data_size = (uint32_t)window_data_len;
    }

    result_code = lzxd_decompress(lzxd, (off_t)dest_len);

    lzxd_free(lzxd);
    lzxd = NULL;
  }
  if (lzxsrc) {
    mspack_memory_close(lzxsrc);
    lzxsrc = NULL;
  }
  if (lzxdst) {
    mspack_memory_close(lzxdst);
    lzxdst = NULL;
  }
  if (sys) {
    mspack_memory_sys_destroy(sys);
    sys = NULL;
  }

  return result_code;
}

int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len,
                         uint32_t window_size, void* dest) {
  void* patch_end = (char*)patch + patch_len;
  auto* cur_patch = patch;

  while (patch_end > cur_patch) {
    int patch_sz = -4;  // 0 byte patches need us to remove 4 byte from next
                        // patch addr because of patch_data field
    if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 &&
        cur_patch->new_addr == 0 && cur_patch->old_addr == 0)
      break;
    switch (cur_patch->compressed_len) {
      case 0:  // fill with 0
        std::memset((char*)dest + cur_patch->new_addr, 0,
                    cur_patch->uncompressed_len);
        break;
      case 1:  // copy from old -> new
        std::memcpy((char*)dest + cur_patch->new_addr,
                    (char*)dest + cur_patch->old_addr,
                    cur_patch->uncompressed_len);
        break;
      default:  // delta patch
        patch_sz =
            cur_patch->compressed_len - 4;  // -4 because of patch_data field

        int result = lzx_decompress(
            cur_patch->patch_data, cur_patch->compressed_len,
            (char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len,
            window_size, (char*)dest + cur_patch->old_addr,
            cur_patch->uncompressed_len);

        if (result) {
          return result;
        }
        break;
    }

    cur_patch++;
    cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch +
                                        patch_sz);  // TODO: make this less ugly
  }

  return 0;
}
<commit_msg>[CPU] Use window size for LZX ref_data_size<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/cpu/lzx.h"

#include <algorithm>
#include <climits>

#include "xenia/base/byte_order.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/memory.h"
#include "xenia/kernel/util/xex2_info.h"

#include "third_party/mspack/lzx.h"
#include "third_party/mspack/mspack.h"

typedef struct mspack_memory_file_t {
  struct mspack_system sys;
  void* buffer;
  off_t buffer_size;
  off_t offset;
} mspack_memory_file;
mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer,
                                       const size_t buffer_size) {
  assert_true(buffer_size < INT_MAX);
  if (buffer_size >= INT_MAX) {
    return NULL;
  }
  mspack_memory_file* memfile =
      (mspack_memory_file*)calloc(1, sizeof(mspack_memory_file));
  if (!memfile) {
    return NULL;
  }
  memfile->buffer = buffer;
  memfile->buffer_size = (off_t)buffer_size;
  memfile->offset = 0;
  return memfile;
}
void mspack_memory_close(mspack_memory_file* file) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  free(memfile);
}
int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  const off_t remaining = memfile->buffer_size - memfile->offset;
  const off_t total = std::min(static_cast<off_t>(chars), remaining);
  std::memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total);
  memfile->offset += total;
  return (int)total;
}
int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) {
  mspack_memory_file* memfile = (mspack_memory_file*)file;
  const off_t remaining = memfile->buffer_size - memfile->offset;
  const off_t total = std::min(static_cast<off_t>(chars), remaining);
  std::memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total);
  memfile->offset += total;
  return (int)total;
}
void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) {
  return std::calloc(chars, 1);
}
void mspack_memory_free(void* ptr) { free(ptr); }
void mspack_memory_copy(void* src, void* dest, size_t chars) {
  std::memcpy(dest, src, chars);
}
struct mspack_system* mspack_memory_sys_create() {
  struct mspack_system* sys =
      (struct mspack_system*)std::calloc(1, sizeof(struct mspack_system));
  if (!sys) {
    return NULL;
  }
  sys->read = mspack_memory_read;
  sys->write = mspack_memory_write;
  sys->alloc = mspack_memory_alloc;
  sys->free = mspack_memory_free;
  sys->copy = mspack_memory_copy;
  return sys;
}
void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); }

int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
                   size_t dest_len, uint32_t window_size, void* window_data,
                   size_t window_data_len) {
  uint32_t window_bits = 0;
  uint32_t temp_sz = window_size;
  for (size_t m = 0; m < 32; m++, window_bits++) {
    temp_sz >>= 1;
    if (temp_sz == 0x00000000) {
      break;
    }
  }

  int result_code = 1;

  mspack_system* sys = mspack_memory_sys_create();
  mspack_memory_file* lzxsrc =
      mspack_memory_open(sys, (void*)lzx_data, lzx_len);
  mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len);
  lzxd_stream* lzxd =
      lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst,
                window_bits, 0, 0x8000, (off_t)dest_len, 0);

  if (lzxd) {
    if (window_data) {
      // zero the window and then copy window_data to the end of it
      std::memset(lzxd->window, 0, window_data_len);
      std::memcpy(lzxd->window + (window_size - window_data_len), window_data,
                  window_data_len);
      lzxd->ref_data_size = window_size;
    }

    result_code = lzxd_decompress(lzxd, (off_t)dest_len);

    lzxd_free(lzxd);
    lzxd = NULL;
  }
  if (lzxsrc) {
    mspack_memory_close(lzxsrc);
    lzxsrc = NULL;
  }
  if (lzxdst) {
    mspack_memory_close(lzxdst);
    lzxdst = NULL;
  }
  if (sys) {
    mspack_memory_sys_destroy(sys);
    sys = NULL;
  }

  return result_code;
}

int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len,
                         uint32_t window_size, void* dest) {
  void* patch_end = (char*)patch + patch_len;
  auto* cur_patch = patch;

  while (patch_end > cur_patch) {
    int patch_sz = -4;  // 0 byte patches need us to remove 4 byte from next
                        // patch addr because of patch_data field
    if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 &&
        cur_patch->new_addr == 0 && cur_patch->old_addr == 0)
      break;
    switch (cur_patch->compressed_len) {
      case 0:  // fill with 0
        std::memset((char*)dest + cur_patch->new_addr, 0,
                    cur_patch->uncompressed_len);
        break;
      case 1:  // copy from old -> new
        std::memcpy((char*)dest + cur_patch->new_addr,
                    (char*)dest + cur_patch->old_addr,
                    cur_patch->uncompressed_len);
        break;
      default:  // delta patch
        patch_sz =
            cur_patch->compressed_len - 4;  // -4 because of patch_data field

        int result = lzx_decompress(
            cur_patch->patch_data, cur_patch->compressed_len,
            (char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len,
            window_size, (char*)dest + cur_patch->old_addr,
            cur_patch->uncompressed_len);

        if (result) {
          return result;
        }
        break;
    }

    cur_patch++;
    cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch +
                                        patch_sz);  // TODO: make this less ugly
  }

  return 0;
}
<|endoftext|>