<commit_before>/*!
*	@file	face.cpp
*	@brief	Functions for mesh faces
*/

#include <set>
#include <iostream>
#include <stdexcept>
#include <limits>
#include "face.h"
#include "edge.h"

namespace psalm
{

/*!
*	Default constructor for the face.
*/

face::face()
{
	face_point	= NULL;
	id		= std::numeric_limits<size_t>::max();
	boundary	= false;
}

/*!
*	Adds an edge to the face.
*
*	@param result Directed edge to add to face
*
*	@warning Edge is not checked for consistency, i.e., you can add edges
*	that are not part of the face.
*/

void face::add_edge(const directed_edge& result)
{
	E.push_back(result);
}

/*!
*	@param	i Index of edge
*	@return Edge at specified index
*/

directed_edge& face::get_edge(size_t i)
{
	return(const_cast<directed_edge&>(static_cast<const face*>(this)->get_edge(i)));
}

/*!
*	@param	i Index of edge
*	@return	Const reference to edge at specified index
*/

const directed_edge& face::get_edge(size_t i) const
{
	if(i >= E.size())
		throw std::out_of_range("face::get_edge(): Invalid edge index");
	else
		return(E[i]);
}

/*!
*	Adds vertex to the face.
*
*	@param v Pointer to new vertex.
*	@warning The vertex is not checked for consistency, i.e., you can add
*	any vertex to the face (even vertices that are not part of the face at
*	all).
*/

void face::add_vertex(vertex* v)
{
	V.push_back(v);
}

/*!
*	@param i Index of vertex
*	@return Vertex at specified index or NULL if the index is out of range.
*/

const vertex* face::get_vertex(size_t i) const
{
	if(i >= V.size())
		return(NULL);
	else
		return(V[i]);
}

/*!
*	@return Number of vertices for face, i.e., whether the face is a
*	triangle, a quadrangle, ...
*/

size_t face::num_vertices() const
{
	return(V.size());
}

/*!
*	@return Number of edges for face
*/

size_t face::num_edges() const
{
	return(E.size());
}

/*!
*	Stores a new face vertex that corresponds to a vertex in the mesh.
*
*	@param v Pointer to new vertex.
*	@warning The new vertex cannot be checked for consistency, i.e., there
*	is no way of finding out whether the new vertex corresponds to a vertex
*	of the face.
*/

void face::add_face_vertex(vertex* v)
{
	V_F.push_back(v);
}

/*!
*	@param i Index of face vertex.
*	@return Face vertex that corresponds to a vertex in the mesh or NULL if
*	the index is out of range.
*/

vertex* face::get_face_vertex(size_t i)
{
	if(i >= V_F.size())
		return(NULL);
	else
		return(V_F[i]);
}

/*!
*	Returns value of flag signalling whether the face is a boundary face.
*	Value of flag is supposed to be set by the user.
*/

bool face::is_on_boundary() const
{
	return(boundary);
}

/*!
*	Sets value of flag signalling boundary faces. The parameter is set to
*	false by default in all constructors.
*
*	@param	boundary Current value for boundary parameter (true by default)
*/

void face::set_on_boundary(bool boundary)
{
	this->boundary = boundary;
}

/*!
*	Reconstructs the face from its edges:
*
*	- Delete vertices
*	- Traverse edges
*	- Store vertices in the order specified by the edges
*/

void face::reconstruct_from_edges()
{
	V.clear();
	std::cout << "HAVE: ";
	for(std::vector<directed_edge>::iterator e_it = E.begin(); e_it < E.end(); e_it++)
	{
		if(e_it->inverted)
			std::cout << "* ";

		std::cout << e_it->e->get_u()->get_id() << " ";
		std::cout << e_it->e->get_v()->get_id() << " ";

		// Only store the first vertex of an edge -- this will yield
		// _all_ vertices upon traversal
		if(e_it->inverted)
			add_vertex(const_cast<vertex*>(e_it->e->get_v())); // XXX: Evil. face::add_vertex() should be fixed
		else
			add_vertex(const_cast<vertex*>(e_it->e->get_u()));
	}
	std::cout << "\n";

	std::set<size_t> V_IDs;

	std::cout << "\tRECONSTRUCTED: ";
	for(size_t i = 0; i < V.size(); i++)
	{
		std::cout << V[i]->get_id() << " ";
		V_IDs.insert(V[i]->get_id());
	}

	std::cout << " [ SORTED: ";
	for(std::set<size_t>::iterator it = V_IDs.begin(); it != V_IDs.end(); it++)
	{
		std::cout << *it << " ";
	}
	std::cout << "] " << "\n";

	if(V_IDs.size() < 3)
		std::cout << "DISASTER.\n";

}

} // end of namespace "psalm"
<commit_msg>Cleanup: Removed debug output from face::reconstruct_from_edges()<commit_after>/*!
*	@file	face.cpp
*	@brief	Functions for mesh faces
*/

#include <set>
#include <iostream>
#include <stdexcept>
#include <limits>
#include "face.h"
#include "edge.h"

namespace psalm
{

/*!
*	Default constructor for the face.
*/

face::face()
{
	face_point	= NULL;
	id		= std::numeric_limits<size_t>::max();
	boundary	= false;
}

/*!
*	Adds an edge to the face.
*
*	@param result Directed edge to add to face
*
*	@warning Edge is not checked for consistency, i.e., you can add edges
*	that are not part of the face.
*/

void face::add_edge(const directed_edge& result)
{
	E.push_back(result);
}

/*!
*	@param	i Index of edge
*	@return Edge at specified index
*/

directed_edge& face::get_edge(size_t i)
{
	return(const_cast<directed_edge&>(static_cast<const face*>(this)->get_edge(i)));
}

/*!
*	@param	i Index of edge
*	@return	Const reference to edge at specified index
*/

const directed_edge& face::get_edge(size_t i) const
{
	if(i >= E.size())
		throw std::out_of_range("face::get_edge(): Invalid edge index");
	else
		return(E[i]);
}

/*!
*	Adds vertex to the face.
*
*	@param v Pointer to new vertex.
*	@warning The vertex is not checked for consistency, i.e., you can add
*	any vertex to the face (even vertices that are not part of the face at
*	all).
*/

void face::add_vertex(vertex* v)
{
	V.push_back(v);
}

/*!
*	@param i Index of vertex
*	@return Vertex at specified index or NULL if the index is out of range.
*/

const vertex* face::get_vertex(size_t i) const
{
	if(i >= V.size())
		return(NULL);
	else
		return(V[i]);
}

/*!
*	@return Number of vertices for face, i.e., whether the face is a
*	triangle, a quadrangle, ...
*/

size_t face::num_vertices() const
{
	return(V.size());
}

/*!
*	@return Number of edges for face
*/

size_t face::num_edges() const
{
	return(E.size());
}

/*!
*	Stores a new face vertex that corresponds to a vertex in the mesh.
*
*	@param v Pointer to new vertex.
*	@warning The new vertex cannot be checked for consistency, i.e., there
*	is no way of finding out whether the new vertex corresponds to a vertex
*	of the face.
*/

void face::add_face_vertex(vertex* v)
{
	V_F.push_back(v);
}

/*!
*	@param i Index of face vertex.
*	@return Face vertex that corresponds to a vertex in the mesh or NULL if
*	the index is out of range.
*/

vertex* face::get_face_vertex(size_t i)
{
	if(i >= V_F.size())
		return(NULL);
	else
		return(V_F[i]);
}

/*!
*	Returns value of flag signalling whether the face is a boundary face.
*	Value of flag is supposed to be set by the user.
*/

bool face::is_on_boundary() const
{
	return(boundary);
}

/*!
*	Sets value of flag signalling boundary faces. The parameter is set to
*	false by default in all constructors.
*
*	@param	boundary Current value for boundary parameter (true by default)
*/

void face::set_on_boundary(bool boundary)
{
	this->boundary = boundary;
}

/*!
*	Reconstructs the face from its edges:
*
*	- Delete vertices
*	- Traverse edges
*	- Store vertices in the order specified by the edges
*/

void face::reconstruct_from_edges()
{
	V.clear();
	for(std::vector<directed_edge>::iterator e_it = E.begin(); e_it < E.end(); e_it++)
	{
		// Only store the first vertex of an edge -- this will yield
		// _all_ vertices upon traversal
		if(e_it->inverted)
			add_vertex(const_cast<vertex*>(e_it->e->get_v())); // XXX: Evil. face::add_vertex() should be fixed
		else
			add_vertex(const_cast<vertex*>(e_it->e->get_u()));
	}
}

} // end of namespace "psalm"
<|endoftext|>


<commit_before>#include <array>
#include <string_view>

#include <tst/set.hpp>
#include <tst/check.hpp>

#include <utki/sort.hpp>

using namespace std::string_view_literals;

namespace{
namespace test_compile_time_sorting{
struct str_num_pair{
	std::string_view first;
	int second;

	constexpr bool operator==(const str_num_pair& p)const{
		return this->first == p.first && this->second == p.second;
	}
};

constexpr auto arr = []()constexpr{
	std::array<str_num_pair, 5> arr = {{
			{"hello"sv, 13},
			{"bye"sv, 15},
			{"how"sv, 33},
			{"are"sv, 4},
			{"you"sv, 9}
		}};

	utki::sort(
			arr.begin(),
			arr.end(),
			[](const auto& a, const auto& b){
				return a.first < b.first;
			}
		);
	return arr;
}();

constexpr decltype(arr) expected = {{
		{"are", 4},
		{"bye", 15},
		{"hello", 13},
		{"how", 33},
		{"you", 9}
	}};

static_assert(
		// the std::array::operator==() is not constexpr in C++17 (it is in C++20), so we need to compare element by element
		[]{
			if(arr.size() != expected.size()){
				return false;
			}
			for(auto i = arr.begin(), j = expected.begin(); i != arr.end(); ++i, ++j){
				if(*i == *j){
					continue;
				}
				return false;
			}
			return true;
		}(),
		"sorted array is not as expected"
	);
}
}

namespace{
tst::set set("sort", [](tst::suite& suite){
	suite.add("compile_time_sort", []{
		tst::check(test_compile_time_sorting::arr == test_compile_time_sorting::expected, SL);
	});

	suite.add("sort_strings_with_default_comparator", []{
		std::array<std::string, 5> arr = {{
			"hello",
			"bye",
			"how",
			"are",
			"you",
		}};

		utki::sort(arr.begin(), arr.end());

		decltype(arr) expected = {{
			"are",
			"bye",
			"hello",
			"how",
			"you",
		}};

		tst::check(arr == expected, SL);
	});

	suite.add("sort_strings_with_custom_comparator", []{
		std::array<std::pair<std::string, int>, 5> arr = {{
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
			{"are", 4},
			{"you", 9}
		}};

		utki::sort(arr.begin(), arr.end(), [](const auto& a, const auto& b){return a.first < b.first;});

		decltype(arr) expected = {{
			{"are", 4},
			{"bye", 15},
			{"hello", 13},
			{"how", 33},
			{"you", 9}
		}};

		tst::check(arr == expected, SL);
	});

	suite.add("sort_integers_with_custom_comparator", []{
		std::array<std::pair<std::string, int>, 5> arr = {{
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
			{"are", 4},
			{"you", 9},
		}};

		utki::sort(arr.begin(), arr.end(), [](const auto& a, const auto& b){return a.second < b.second;});

		decltype(arr) expected = {{
			{"are", 4},
			{"you", 9},
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
		}};

		tst::check(arr == expected, SL);
	});
});
}
<commit_msg>fix msvs build<commit_after>#include <array>
#include <string_view>

#include <tst/set.hpp>
#include <tst/check.hpp>

#include <utki/sort.hpp>

using namespace std::string_view_literals;

#if M_COMPILER != M_COMPILER_MSVC || M_COMPILER_MSVC_TOOLS_V >= 142
namespace{
namespace test_compile_time_sorting{
struct str_num_pair{
	std::string_view first;
	int second;

	constexpr bool operator==(const str_num_pair& p)const{
		return this->first == p.first && this->second == p.second;
	}
};

constexpr auto arr = []()constexpr{
	std::array<str_num_pair, 5> arr = {{
			{"hello"sv, 13},
			{"bye"sv, 15},
			{"how"sv, 33},
			{"are"sv, 4},
			{"you"sv, 9}
		}};

	utki::sort(
			arr.begin(),
			arr.end(),
			[](const auto& a, const auto& b){
				return a.first < b.first;
			}
		);
	return arr;
}();

constexpr decltype(arr) expected = {{
		{"are", 4},
		{"bye", 15},
		{"hello", 13},
		{"how", 33},
		{"you", 9}
	}};

static_assert(
		// the std::array::operator==() is not constexpr in C++17 (it is in C++20), so we need to compare element by element
		[]{
			if(arr.size() != expected.size()){
				return false;
			}
			for(auto i = arr.begin(), j = expected.begin(); i != arr.end(); ++i, ++j){
				if(*i == *j){
					continue;
				}
				return false;
			}
			return true;
		}(),
		"sorted array is not as expected"
	);
}
}
#endif

namespace{
tst::set set("sort", [](tst::suite& suite){
	suite.add("compile_time_sort", []{
		tst::check(test_compile_time_sorting::arr == test_compile_time_sorting::expected, SL);
	});

	suite.add("sort_strings_with_default_comparator", []{
		std::array<std::string, 5> arr = {{
			"hello",
			"bye",
			"how",
			"are",
			"you",
		}};

		utki::sort(arr.begin(), arr.end());

		decltype(arr) expected = {{
			"are",
			"bye",
			"hello",
			"how",
			"you",
		}};

		tst::check(arr == expected, SL);
	});

	suite.add("sort_strings_with_custom_comparator", []{
		std::array<std::pair<std::string, int>, 5> arr = {{
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
			{"are", 4},
			{"you", 9}
		}};

		utki::sort(arr.begin(), arr.end(), [](const auto& a, const auto& b){return a.first < b.first;});

		decltype(arr) expected = {{
			{"are", 4},
			{"bye", 15},
			{"hello", 13},
			{"how", 33},
			{"you", 9}
		}};

		tst::check(arr == expected, SL);
	});

	suite.add("sort_integers_with_custom_comparator", []{
		std::array<std::pair<std::string, int>, 5> arr = {{
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
			{"are", 4},
			{"you", 9},
		}};

		utki::sort(arr.begin(), arr.end(), [](const auto& a, const auto& b){return a.second < b.second;});

		decltype(arr) expected = {{
			{"are", 4},
			{"you", 9},
			{"hello", 13},
			{"bye", 15},
			{"how", 33},
		}};

		tst::check(arr == expected, SL);
	});
});
}
<|endoftext|>


<commit_before>// Copyright (c) 2007, 2008 libmv authors.
//
// 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.
//
// Compute a projective reconstruction from N views of six points. Based on:
//
// [1] Frederik Schaffalitzky, Andrew Zisserman, Richard I. Hartley, Philip H.
// S. Torr. A Six Point Solution for Structure and Motion.  Lecture Notes In
// Computer Science; Vol. 1842 archive Proceedings of the 6th European
// Conference on Computer Vision-Part I pp 632-648, 2000.

#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/fundamental.h"
#include "libmv/multiview/sixpointnview.h"
#include "libmv/numeric/numeric.h"
#include "libmv/numeric/poly.h"

namespace libmv {

/**
 * Compute a pencil of two cameras that both perfectly project the five points
 * to the five basis points of P^3.
 */
template<typename TMatP, typename TMatA, typename TMatB>
static void FivePointCameraPencil(const TMatP &points, TMatA *A, TMatB *B) {
  CHECK_EQ(5, points.cols());
  Mat3 H;
  PreconditionerFromPoints(points, &H);
  Mat35 design = H * points;

  Vec5 v1, v2;
  Nullspace2(&design, &v1, &v2);

  Mat34 five_points = design.block<3,4>(0, 0);
  Mat34 tmpA = five_points;
  Mat34 tmpB = five_points;
  for (int r = 0; r < 3; ++r) {
    // The last component of v1 and v2 is ignored, because it is a scale factor.
    tmpA.row(r) = five_points.row(r).cwise() * v1.start(4).transpose();
    tmpB.row(r) = five_points.row(r).cwise() * v2.start(4).transpose();
  }
  Mat3 Hinv = H.inverse();
  *A = Hinv * tmpA;
  *B = Hinv * tmpB;
}

/** Calculate the last (sixth) point in projective 4 space. */
static Vec4 CalcX6FromDesignMat(
    double a, double b, double c, double d, double e) {
  // This should match the matrix in step 6 above, equation (9) in [1].
  // The 6th world point is the nullspace of this matrix.
  Mat X6null(6,4);
  X6null << e-d,  0 ,  0 , a-b,
            e-c,  0 ,  a ,  0 ,
            d-c,  b ,  0 ,  0 ,
             0 ,  e ,  0 , a-c,
             0 , e-b, a-d,  0 ,
             0 ,  0 ,  d , b-c;
  Vec4 X6;
  Nullspace(&X6null, &X6);
  return X6;
}

// See paragraph after equation 16 in torr97robust for the equation used to
// derive the following coefficients.
#define ACCUMULATE_CUBIC_COEFFICIENTS(x,y,z, sgn) \
  p = t1[x]*t1[y]; \
  q = t2[x]*t1[y] + t1[x]*t2[y]; \
  d += sgn *  p*t1[z]; \
  c += sgn * (q*t1[z] + p*t2[z]); \
  b += sgn * (t2[x]*t2[y]*t1[z] + q*t2[z]); \
  a += sgn *  t2[x]*t2[y]*t2[z];

// TODO(keir): Break this up into smaller functions.
// TODO(keir): Change 'points' from 2 x 6nviews to be 2n views x 6; this way it
// can be directly passed from the robust estimation code without copying.
void SixPointNView(const Mat2X &points,
                   vector<SixPointReconstruction> *reconstructions) {
  CHECK(points.cols() % 6 == 0);
  int nviews = points.cols() / 6;

  // Convert to homogeneous coordinates.
  Mat3X hpoints(3, points.cols());
  hpoints.block(0, 0, 2, 6*nviews) = points;
  hpoints.row(2).setOnes();

  // See equation (7.2) p179 of HZ; this is the DLT for solving cameras.
  // Chose wi = 1, i.e. the homogeneous component of each image location is 1.
  // Note that As and Bs are on the heap to avoid blowing the stack for a large
  // number of views.
  Mat34 *As = new Mat34[nviews];
  Mat34 *Bs = new Mat34[nviews];
  Mat ws(nviews,5);

  for (int i = 0; i < nviews; ++i) {
    // Extract pencil of camera matrices.
    FivePointCameraPencil(hpoints.block(0, 6*i, 3, 5), As+i, Bs+i);

    // Calculate Q.
    Vec3 x6 = hpoints.col(6*i+5);
    Mat3 x6cross = CrossProductMatrix(x6);
    Mat4 Qa = As[i].transpose() * x6cross * Bs[i];
    Mat4 Q = Qa + Qa.transpose();

    // Read the coefficients w^i from Q and put into the ws matrix.
    ws(i,0) = Q(0,1);
    ws(i,1) = Q(0,2);
    ws(i,2) = Q(1,2);
    ws(i,3) = Q(1,3);
    ws(i,4) = Q(2,3);
  }
  Vec t1, t2;
  Nullspace2(&ws, &t1, &t2);

  // The svd gives us the basis for the nullspace of ws in which the t vector
  // lives, such that t = beta*t1+alpha*t2. However, there is a cubic
  // constraint on the elements of t, such that we can substitute and solve for
  // alpha. See equation (10) in [1].
  double a, b, c, d, p, q;
  a = b = c = d = 0;
  ACCUMULATE_CUBIC_COEFFICIENTS(0,1,3,  1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,1,4, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,2,4,  1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,3,4, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(1,2,3, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(1,3,4,  1);

  // TODO(keir): Handle case a = 0.
  // TODO(keir): Handle the case (a=b=c=d=0. If a=b=c=0 and d!=0, then alpha=0;
  // in that case, find beta instead.
  CHECK(a != 0.0);
  // Assume beta = 1.
  double a1 = b/a, b1 = c/a, c1 = d/a;
  a = a1;
  b = b1;
  c = c1;

  double alpha, alphas[3];
  int nroots = SolveCubicPolynomial(a, b, c, alphas+0, alphas+1, alphas+2);

  // Check each solution for alpha.
  reconstructions->resize(nroots);
  for (int ia=0; ia<nroots; ia++) {
    alpha = alphas[ia];

    double e;
    a = t1[0] + alpha*t2[0];
    b = t1[1] + alpha*t2[1];
    c = t1[2] + alpha*t2[2];
    d = t1[3] + alpha*t2[3];
    e = t1[4] + alpha*t2[4];

    SixPointReconstruction &pr = (*reconstructions)[ia];

    // The world position of the first five points, X1 through X5, are the
    // standard P^3 basis.
    pr.X.block<4, 4>(0, 0).setIdentity();
    pr.X.col(4).setOnes();

    // Find X6 from the chi vector.
    Vec4 Xp = CalcX6FromDesignMat(a, b, c, d, e);
    pr.X.col(5) = Xp;

    // Find P for each camera by finding suitable values of u,v.
    pr.P.resize(nviews);
    for (int i = 0; i < nviews; ++i) {
      // Project X6 with A and B. DO NOT NORMALIZE, it breaks the next step.
      Vec3 AX = As[i] * Xp;
      Vec3 BX = Bs[i] * Xp;

      // Find mu and nu with smallest algebraic error; see step 7. For exactly
      // six points, M will be rank 2. With more than 6 points, measurement
      // error will make M nonsingular.
      Mat3 M;
      M.col(0) = AX;
      M.col(1) = BX;
      M.col(2) = hpoints.col(6*i+5);  // x6.

      Vec3 munu;
      Nullspace(&M, &munu);
      double mu = munu[0];
      double nu = munu[1];

      pr.P[i] = mu*As[i] + nu*Bs[i];
    }
  }
  delete [] As;
  delete [] Bs;
}

} // namespace libmv
<commit_msg>Fix for visual 10 release mode.<commit_after>// Copyright (c) 2007, 2008 libmv authors.
//
// 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.
//
// Compute a projective reconstruction from N views of six points. Based on:
//
// [1] Frederik Schaffalitzky, Andrew Zisserman, Richard I. Hartley, Philip H.
// S. Torr. A Six Point Solution for Structure and Motion.  Lecture Notes In
// Computer Science; Vol. 1842 archive Proceedings of the 6th European
// Conference on Computer Vision-Part I pp 632-648, 2000.

#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/fundamental.h"
#include "libmv/multiview/sixpointnview.h"
#include "libmv/numeric/numeric.h"
#include "libmv/numeric/poly.h"

namespace libmv {

/**
 * Compute a pencil of two cameras that both perfectly project the five points
 * to the five basis points of P^3.
 */
template<typename TMatP, typename TMatA, typename TMatB>
static void FivePointCameraPencil(const TMatP &points, TMatA *A, TMatB *B) {
  CHECK(5 == points.cols());
  Mat3 H;
  PreconditionerFromPoints(points, &H);
  Mat35 design = H * points;

  Vec5 v1, v2;
  Nullspace2(&design, &v1, &v2);

  Mat34 five_points = design.block<3,4>(0, 0);
  Mat34 tmpA = five_points;
  Mat34 tmpB = five_points;
  for (int r = 0; r < 3; ++r) {
    // The last component of v1 and v2 is ignored, because it is a scale factor.
    tmpA.row(r) = five_points.row(r).cwise() * v1.start(4).transpose();
    tmpB.row(r) = five_points.row(r).cwise() * v2.start(4).transpose();
  }
  Mat3 Hinv = H.inverse();
  *A = Hinv * tmpA;
  *B = Hinv * tmpB;
}

/** Calculate the last (sixth) point in projective 4 space. */
static Vec4 CalcX6FromDesignMat(
    double a, double b, double c, double d, double e) {
  // This should match the matrix in step 6 above, equation (9) in [1].
  // The 6th world point is the nullspace of this matrix.
  Mat X6null(6,4);
  X6null << e-d,  0 ,  0 , a-b,
            e-c,  0 ,  a ,  0 ,
            d-c,  b ,  0 ,  0 ,
             0 ,  e ,  0 , a-c,
             0 , e-b, a-d,  0 ,
             0 ,  0 ,  d , b-c;
  Vec4 X6;
  Nullspace(&X6null, &X6);
  return X6;
}

// See paragraph after equation 16 in torr97robust for the equation used to
// derive the following coefficients.
#define ACCUMULATE_CUBIC_COEFFICIENTS(x,y,z, sgn) \
  p = t1[x]*t1[y]; \
  q = t2[x]*t1[y] + t1[x]*t2[y]; \
  d += sgn *  p*t1[z]; \
  c += sgn * (q*t1[z] + p*t2[z]); \
  b += sgn * (t2[x]*t2[y]*t1[z] + q*t2[z]); \
  a += sgn *  t2[x]*t2[y]*t2[z];

// TODO(keir): Break this up into smaller functions.
// TODO(keir): Change 'points' from 2 x 6nviews to be 2n views x 6; this way it
// can be directly passed from the robust estimation code without copying.
void SixPointNView(const Mat2X &points,
                   vector<SixPointReconstruction> *reconstructions) {
  CHECK(points.cols() % 6 == 0);
  int nviews = points.cols() / 6;

  // Convert to homogeneous coordinates.
  Mat3X hpoints(3, points.cols());
  hpoints.block(0, 0, 2, 6*nviews) = points;
  hpoints.row(2).setOnes();

  // See equation (7.2) p179 of HZ; this is the DLT for solving cameras.
  // Chose wi = 1, i.e. the homogeneous component of each image location is 1.
  // Note that As and Bs are on the heap to avoid blowing the stack for a large
  // number of views.
  Mat34 *As = new Mat34[nviews];
  Mat34 *Bs = new Mat34[nviews];
  Mat ws(nviews,5);

  for (int i = 0; i < nviews; ++i) {
    // Extract pencil of camera matrices.
    FivePointCameraPencil(hpoints.block(0, 6*i, 3, 5), As+i, Bs+i);

    // Calculate Q.
    Vec3 x6 = hpoints.col(6*i+5);
    Mat3 x6cross = CrossProductMatrix(x6);
    Mat4 Qa = As[i].transpose() * x6cross * Bs[i];
    Mat4 Q = Qa + Qa.transpose();

    // Read the coefficients w^i from Q and put into the ws matrix.
    ws(i,0) = Q(0,1);
    ws(i,1) = Q(0,2);
    ws(i,2) = Q(1,2);
    ws(i,3) = Q(1,3);
    ws(i,4) = Q(2,3);
  }
  Vec t1, t2;
  Nullspace2(&ws, &t1, &t2);

  // The svd gives us the basis for the nullspace of ws in which the t vector
  // lives, such that t = beta*t1+alpha*t2. However, there is a cubic
  // constraint on the elements of t, such that we can substitute and solve for
  // alpha. See equation (10) in [1].
  double a, b, c, d, p, q;
  a = b = c = d = 0;
  ACCUMULATE_CUBIC_COEFFICIENTS(0,1,3,  1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,1,4, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,2,4,  1);
  ACCUMULATE_CUBIC_COEFFICIENTS(0,3,4, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(1,2,3, -1);
  ACCUMULATE_CUBIC_COEFFICIENTS(1,3,4,  1);

  // TODO(keir): Handle case a = 0.
  // TODO(keir): Handle the case (a=b=c=d=0. If a=b=c=0 and d!=0, then alpha=0;
  // in that case, find beta instead.
  CHECK(a != 0.0);
  // Assume beta = 1.
  double a1 = b/a, b1 = c/a, c1 = d/a;
  a = a1;
  b = b1;
  c = c1;

  double alpha, alphas[3];
  int nroots = SolveCubicPolynomial(a, b, c, alphas+0, alphas+1, alphas+2);

  // Check each solution for alpha.
  reconstructions->resize(nroots);
  for (int ia=0; ia<nroots; ia++) {
    alpha = alphas[ia];

    double e;
    a = t1[0] + alpha*t2[0];
    b = t1[1] + alpha*t2[1];
    c = t1[2] + alpha*t2[2];
    d = t1[3] + alpha*t2[3];
    e = t1[4] + alpha*t2[4];

    SixPointReconstruction &pr = (*reconstructions)[ia];

    // The world position of the first five points, X1 through X5, are the
    // standard P^3 basis.
    pr.X.block<4, 4>(0, 0).setIdentity();
    pr.X.col(4).setOnes();

    // Find X6 from the chi vector.
    Vec4 Xp = CalcX6FromDesignMat(a, b, c, d, e);
    pr.X.col(5) = Xp;

    // Find P for each camera by finding suitable values of u,v.
    pr.P.resize(nviews);
    for (int i = 0; i < nviews; ++i) {
      // Project X6 with A and B. DO NOT NORMALIZE, it breaks the next step.
      Vec3 AX = As[i] * Xp;
      Vec3 BX = Bs[i] * Xp;

      // Find mu and nu with smallest algebraic error; see step 7. For exactly
      // six points, M will be rank 2. With more than 6 points, measurement
      // error will make M nonsingular.
      Mat3 M;
      M.col(0) = AX;
      M.col(1) = BX;
      M.col(2) = hpoints.col(6*i+5);  // x6.

      Vec3 munu;
      Nullspace(&M, &munu);
      double mu = munu[0];
      double nu = munu[1];

      pr.P[i] = mu*As[i] + nu*Bs[i];
    }
  }
  delete [] As;
  delete [] Bs;
}

} // namespace libmv
<|endoftext|>


<commit_before>//
// Copyright (C) 2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Keith Kyzivat <kkyzivat AT SIPez DOT com>

// SYSTEM INCLUDES
#include <os/OsSysLog.h>

// APPLICATION INCLUDES
#include "mp/MpidWinMM.h"
#include "mp/MpInputDeviceManager.h"

// EXTERNAL FUNCTIONS
extern void showWaveError(char *syscall, int e, int N, int line) ;  // dmaTaskWnt.cpp

// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// DEFINES
#if defined(_MSC_VER) && (_MSC_VER < 1300) // if < msvc7 (2003)
#  define CBTYPE DWORD
#else
#  define CBTYPE DWORD_PTR
#endif

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */
// Default constructor
MpidWinMM::MpidWinMM(const UtlString& name,
                     MpInputDeviceManager& deviceManager,
                     unsigned nInputBuffers)
: MpInputDeviceDriver(name, deviceManager)
, mWinMMDeviceId(-1)
, mDevHandle(NULL)
, mNumInBuffers(nInputBuffers)
, mWaveBufSize(0)  // Unknown until enableDevice()
, mIsOpen(FALSE)
, mnAddBufferFailures(0)
{
    WAVEINCAPS devCaps;
    // Grab the number of input devices that are available.
    UINT nInputDevs = waveInGetNumDevs();

    // Search through the input devices looking for the input device specified.
    MMRESULT wavResult = MMSYSERR_NOERROR;
    unsigned i;
    for (i = 0; i < nInputDevs; i++)
    {
        MMRESULT res = waveInGetDevCaps(i, &devCaps, sizeof(devCaps));
        if (res != MMSYSERR_NOERROR)
        {
            wavResult = res;
        }
        else if (strncmp(name, devCaps.szPname, MAXPNAMELEN) == 0)
        {
            mWinMMDeviceId = i;
            break;
        }
    }

    // Allocate the wave headers and buffer pointers for use with
    // windows audio routines.
    //(This does *not* include allocation of the buffers themselves -
    // that is handled in enableDevice, as we don't know the
    // buffer size (#samplesPerFrame) until then.
    mpWaveHeaders = new WAVEHDR[mNumInBuffers];
    mpWaveBuffers = new LPSTR[mNumInBuffers];
    for (i = 0; i < mNumInBuffers; i++)
    {
        mpWaveBuffers[i] = NULL;
    }
}

// Destructor
MpidWinMM::~MpidWinMM()
{
    // If we happen to still be enabled at this point, disable the device.
    assert(!isEnabled());
    if (isEnabled())
    {
        disableDevice();
    }

    // Delete the sample headers and sample buffer pointers..
    unsigned i;
    for (i = 0; i < mNumInBuffers; i++)
    {
        assert(mpWaveBuffers[i] == NULL);
        if (mpWaveBuffers[i] != NULL)
        {
            delete[] mpWaveBuffers[i];
            mpWaveBuffers[i] = NULL;
        }
    }
    delete[] mpWaveBuffers;
    delete[] mpWaveHeaders;
}

/* ============================ MANIPULATORS ============================== */

OsStatus MpidWinMM::enableDevice(unsigned samplesPerFrame,
                                 unsigned samplesPerSec,
                                 MpFrameTime currentFrameTime)
{
    OsStatus status = OS_SUCCESS;

    // reset the number of addBuffer failures, as we're starting fresh now.
    mnAddBufferFailures = 0;

    // If the device is not valid, let the user know it's bad.
    if (!isDeviceValid())
    {
        return OS_INVALID_STATE;  // perhaps new OsState of OS_RESOURCE_INVALID?
    }

    if (isEnabled())
    {
        return OS_FAILED;
    }

    // Set some wave header stat information.
    mSamplesPerFrame = samplesPerFrame;
    mSamplesPerSec = samplesPerSec;
    mCurrentFrameTime = currentFrameTime;

    // Do stuff to enable device.
    int nChannels = 1;
    WAVEFORMATEX wavFormat;
    wavFormat.wFormatTag = WAVE_FORMAT_PCM;
    wavFormat.nChannels = nChannels;
    wavFormat.nSamplesPerSec = mSamplesPerSec;
    wavFormat.nAvgBytesPerSec =
        nChannels * mSamplesPerSec * sizeof(MpAudioSample);
    wavFormat.nBlockAlign = nChannels * sizeof(MpAudioSample);
    wavFormat.wBitsPerSample = sizeof(MpAudioSample) * 8;
    wavFormat.cbSize = 0;

    // Tell windows to open the input audio device.  This doesn't
    // tell it to send the data to our callback yet, just to get it ready
    // to do so..
    MMRESULT res = waveInOpen(&mDevHandle, mWinMMDeviceId,
                              &wavFormat,
                              (CBTYPE)waveInCallbackStatic,
                              (CBTYPE)this,
                              CALLBACK_FUNCTION);
    if (res != MMSYSERR_NOERROR)
    {
        // If waveInOpen failed, print out the error info,
        // invalidate the handle, and the device driver itself,
        status = OS_FAILED;
        showWaveError("MpidWinMM::enableDevice", res, -1, __LINE__);
        waveInClose(mDevHandle);
        mDevHandle = NULL; // Open didn't work, reset device handle to NULL
        mWinMMDeviceId = -1; // Make device invalid.

        // and return OS_FAILED.
        return status;
    }

    // Allocate the buffers we are going to use to receive audio data from
    // the windows audio input callback.
    // Calculate the buffer length we're going to use.
    // number of samples per frame * sample size in bytes
    mWaveBufSize = mSamplesPerFrame * sizeof(MpAudioSample);
    unsigned i;
    for (i = 0; i < mNumInBuffers; i++)
    {
        mpWaveBuffers[i] = new char[mWaveBufSize];
    }

    // Setup the buffers so windows can stuff them full of audio
    // when it becomes available from this audio input device.
    WAVEHDR* pWaveHdr = NULL;
    for (i=0; i < mNumInBuffers; i++)
    {
        pWaveHdr = initWaveHeader(i);

        res = waveInPrepareHeader(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInPrepareHeader", res, i, __LINE__);
            waveInClose(mDevHandle);
            mDevHandle = NULL;
            mWinMMDeviceId = -1;

            // and return OS_FAILED.
            return status;
        }
        res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInAddBuffer", res, i, __LINE__);
            waveInClose(mDevHandle);
            mDevHandle = NULL;
            mWinMMDeviceId = -1;

            // and return OS_FAILED.
            return status;
        }
    }

    // Tell windows to start sending audio data to the callback.
    res = waveInStart(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        // If waveInStart failed, print out the error info,
        // invalidate the handle and the device driver itself,
        status = OS_FAILED;
        showWaveError("waveInStart", res, -1, __LINE__);
        waveInClose(mDevHandle);
        mDevHandle = NULL;
        mWinMMDeviceId = -1;

        // and return OS_FAILED.
        return status;
    }

    // If enableDevice failed, return indicating failure.
    if (status == OS_SUCCESS)
    {
        mIsEnabled = TRUE;
    }

    return status;
}

OsStatus MpidWinMM::disableDevice()
{
    OsStatus status = OS_SUCCESS;
    MMRESULT   res;

    if (!isDeviceValid() || !isEnabled())
    {
        return OS_FAILED;
    }

    // Indicate we are no longer enabled -- Do this first,
    // since we'll be partially disabled from here on out.
    // It is very important that this happen *before* waveInReset,
    // as the callback will continue to add and process buffers
    // while waveInReset is called causing a deadlock.
    mIsEnabled = FALSE;

    // Cleanup
    if (mDevHandle == NULL)
    {
        return OS_INVALID_STATE;
    }

    // Reset performs a stop, resets the buffers, and marks them
    // for being sent to the callback.
    // The remaining data in the windows buffers *IS* sent to the callback,
    // So be sure to watch for it and drop it on the floor.
    res = waveInReset(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        showWaveError("waveInReset", res, -1, __LINE__);
    }

    // Must unprepare the headers after a reset, but before the device is closed
    // (if this is done after waveInClose, mDevHandle will be invalid and
    // MMSYSERR_INVALHANDLE will be returned.
    unsigned i;
    for (i=0; i < mNumInBuffers; i++)
    {
        res = waveInUnprepareHeader(mDevHandle, &mpWaveHeaders[i], sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInUnprepareHeader", res, i, __LINE__);
        }
    }

    res = waveInClose(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        showWaveError("waveInClose", res, -1, __LINE__);
    }

    // Delete the buffers that were allocated in enableDevice()
    for (i = 0; i < mNumInBuffers; i++)
    {
        delete[] mpWaveBuffers[i];
        mpWaveBuffers[i] = NULL;
    }

    // set the device handle to NULL, since it no longer is valid.
    mDevHandle = NULL;

    // Clear out all the wave header information.
    mSamplesPerFrame = 0;
    mSamplesPerSec = 0;
    mCurrentFrameTime = 0;

    return status;
}

/* ============================ ACCESSORS ================================= */

/* ////////////////////////// PUBLIC STATIC ///////////////////////////////// */
UtlString MpidWinMM::getDefaultDeviceName()
{
   UtlString devName = "";

   // Get windows default input device name
   unsigned nDevs = waveInGetNumDevs();
   if (nDevs == 0)
   {
      OsSysLog::add(FAC_AUDIO, PRI_ERR,
                    "MpidWinMM::getDefaultDeviceName: "
                    "No input audio devices present!");
   }
   assert(nDevs != 0);

   MMRESULT wavResult = MMSYSERR_NOERROR;
   WAVEINCAPS devCaps;
   int defaultWinDeviceId = 0;
   wavResult =
      waveInGetDevCaps(defaultWinDeviceId, &devCaps, sizeof(devCaps));
   if (wavResult != MMSYSERR_NOERROR)
   {
      OsSysLog::add(FAC_AUDIO, PRI_ERR,
                    "MpodWinMM::getDefaultDeviceName: "
                    "Couldn't get default input device capabilities!");
      showWaveError("WINDOWS_DEFAULT_DEVICE_HACK",
                    wavResult, -1, __LINE__);
   }
   else
   {
      devName = devCaps.szPname;
   }
   assert(wavResult == MMSYSERR_NOERROR);
   return devName;
}

/* ============================ INQUIRY =================================== */
/* //////////////////////////// PROTECTED ///////////////////////////////// */

WAVEHDR* MpidWinMM::initWaveHeader(int n)
{
    assert((n >= 0) && (n < (int)mNumInBuffers));
    assert(mpWaveHeaders != NULL);
    assert((mpWaveBuffers != NULL) && (mpWaveBuffers[n] != NULL));
    WAVEHDR* pWave_hdr = &(mpWaveHeaders[n]);
    LPSTR    wave_data(mpWaveBuffers[n]);

    // zero out the wave buffer.
    memset(wave_data, 0, mWaveBufSize);

    // Set wave header data to initial values.
    pWave_hdr->lpData = wave_data;
    pWave_hdr->dwBufferLength = mWaveBufSize;
    pWave_hdr->dwBytesRecorded = 0;  // Filled in by wave functions
    pWave_hdr->dwUser = n;
    pWave_hdr->dwFlags = 0;
    pWave_hdr->dwLoops = 0;
    pWave_hdr->lpNext = NULL;
    pWave_hdr->reserved = 0;

    return pWave_hdr;
}
void MpidWinMM::processAudioInput(HWAVEIN hwi,
                                  UINT uMsg,
                                  void* dwParam1)
{
    if (!mIsOpen)
    {
        assert(uMsg == WIM_OPEN);
        if (uMsg == WIM_OPEN)
        {
            //printf("received WIM_OPEN\n");
            mIsOpen = TRUE;
        }
    }
    if (uMsg == WIM_DATA)
    {
        //printf("received WIM_DATA\n");
        assert(mIsOpen);
        WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1;
        assert(pWaveHdr->dwBufferLength
               == (mSamplesPerFrame*sizeof(MpAudioSample)));
        assert(pWaveHdr->lpData != NULL);

        // Only process if we're enabled..
        if(mIsEnabled)
        {
           mpInputDeviceManager->pushFrame(mDeviceId,
                                           mSamplesPerFrame,
                                           (MpAudioSample*)pWaveHdr->lpData,
                                           mCurrentFrameTime);
           // Ok, we have received and pushed a frame to the manager,
           // Now we advance the frame time.
           mCurrentFrameTime += (mSamplesPerFrame*1000)/mSamplesPerSec;
        }

        if(mIsEnabled)
        {
           // Put the wave header back in the pool..
           MMRESULT res = MMSYSERR_NOERROR;

           res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
           if (res != MMSYSERR_NOERROR)
           {
              showWaveError("waveInAddBuffer", res, -1, __LINE__);
              mnAddBufferFailures++;
              if(mnAddBufferFailures >= mNumInBuffers)
              {
                 waveInClose(mDevHandle);
                 mDevHandle = NULL;
                 mWinMMDeviceId = -1;
              }
           }
        }
    }
    else if (uMsg == WIM_CLOSE)
    {
        printf("received WIM_CLOSE\n");
        mIsOpen = FALSE;
    }
}

void CALLBACK
MpidWinMM::waveInCallbackStatic(HWAVEIN hwi,
                                UINT uMsg,
                                void* dwInstance,
                                void* dwParam1,
                                void* dwParam2)
{
    assert(dwInstance != NULL);
    MpidWinMM* iddWntPtr = (MpidWinMM*)dwInstance;
    assert((uMsg == WIM_OPEN) || (hwi == iddWntPtr->mDevHandle));
    iddWntPtr->processAudioInput(hwi, uMsg, dwParam1);
}

/* //////////////////////////// PRIVATE /////////////////////////////////// */
<commit_msg>Minor cleanup and disabling of debug output in MpidWinMM.<commit_after>//
// Copyright (C) 2007 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2007 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// Author: Keith Kyzivat <kkyzivat AT SIPez DOT com>

// SYSTEM INCLUDES
#include <os/OsSysLog.h>

// APPLICATION INCLUDES
#include "mp/MpidWinMM.h"
#include "mp/MpInputDeviceManager.h"

// EXTERNAL FUNCTIONS
extern void showWaveError(char *syscall, int e, int N, int line) ;  // dmaTaskWnt.cpp

// EXTERNAL VARIABLES
// CONSTANTS
// STATIC VARIABLE INITIALIZATIONS
// DEFINES
#if defined(_MSC_VER) && (_MSC_VER < 1300) // if < msvc7 (2003)
#  define CBTYPE DWORD
#else
#  define CBTYPE DWORD_PTR
#endif

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */
// Default constructor
MpidWinMM::MpidWinMM(const UtlString& name,
                     MpInputDeviceManager& deviceManager,
                     unsigned nInputBuffers)
: MpInputDeviceDriver(name, deviceManager)
, mWinMMDeviceId(-1)
, mDevHandle(NULL)
, mNumInBuffers(nInputBuffers)
, mWaveBufSize(0)  // Unknown until enableDevice()
, mIsOpen(FALSE)
, mnAddBufferFailures(0)
{
    WAVEINCAPS devCaps;
    // Grab the number of input devices that are available.
    UINT nInputDevs = waveInGetNumDevs();

    // Search through the input devices looking for the input device specified.
    MMRESULT wavResult = MMSYSERR_NOERROR;
    unsigned i;
    for (i = 0; i < nInputDevs; i++)
    {
        MMRESULT res = waveInGetDevCaps(i, &devCaps, sizeof(devCaps));
        if (res != MMSYSERR_NOERROR)
        {
            wavResult = res;
        }
        else if (strncmp(name, devCaps.szPname, MAXPNAMELEN) == 0)
        {
            mWinMMDeviceId = i;
            break;
        }
    }

    // Allocate the wave headers and buffer pointers for use with
    // windows audio routines.
    //(This does *not* include allocation of the buffers themselves -
    // that is handled in enableDevice, as we don't know the
    // buffer size (#samplesPerFrame) until then.
    mpWaveHeaders = new WAVEHDR[mNumInBuffers];
    mpWaveBuffers = new LPSTR[mNumInBuffers];
    for (i = 0; i < mNumInBuffers; i++)
    {
        mpWaveBuffers[i] = NULL;
    }
}

// Destructor
MpidWinMM::~MpidWinMM()
{
    // If we happen to still be enabled at this point, disable the device.
    assert(!isEnabled());
    if (isEnabled())
    {
        disableDevice();
    }

    // Delete the sample headers and sample buffer pointers..
    unsigned i;
    for (i = 0; i < mNumInBuffers; i++)
    {
        assert(mpWaveBuffers[i] == NULL);
        if (mpWaveBuffers[i] != NULL)
        {
            delete[] mpWaveBuffers[i];
            mpWaveBuffers[i] = NULL;
        }
    }
    delete[] mpWaveBuffers;
    delete[] mpWaveHeaders;
}

/* ============================ MANIPULATORS ============================== */

OsStatus MpidWinMM::enableDevice(unsigned samplesPerFrame,
                                 unsigned samplesPerSec,
                                 MpFrameTime currentFrameTime)
{
    OsStatus status = OS_SUCCESS;

    // reset the number of addBuffer failures, as we're starting fresh now.
    mnAddBufferFailures = 0;

    // If the device is not valid, let the user know it's bad.
    if (!isDeviceValid())
    {
        return OS_INVALID_STATE;  // perhaps new OsState of OS_RESOURCE_INVALID?
    }

    if (isEnabled())
    {
        return OS_FAILED;
    }

    // Set some wave header stat information.
    mSamplesPerFrame = samplesPerFrame;
    mSamplesPerSec = samplesPerSec;
    mCurrentFrameTime = currentFrameTime;

    // Do stuff to enable device.
    int nChannels = 1;
    WAVEFORMATEX wavFormat;
    wavFormat.wFormatTag = WAVE_FORMAT_PCM;
    wavFormat.nChannels = nChannels;
    wavFormat.nSamplesPerSec = mSamplesPerSec;
    wavFormat.nAvgBytesPerSec =
        nChannels * mSamplesPerSec * sizeof(MpAudioSample);
    wavFormat.nBlockAlign = nChannels * sizeof(MpAudioSample);
    wavFormat.wBitsPerSample = sizeof(MpAudioSample) * 8;
    wavFormat.cbSize = 0;

    // Tell windows to open the input audio device.  This doesn't
    // tell it to send the data to our callback yet, just to get it ready
    // to do so..
    MMRESULT res = waveInOpen(&mDevHandle, mWinMMDeviceId,
                              &wavFormat,
                              (CBTYPE)waveInCallbackStatic,
                              (CBTYPE)this,
                              CALLBACK_FUNCTION);
    if (res != MMSYSERR_NOERROR)
    {
        // If waveInOpen failed, print out the error info,
        // invalidate the handle, and the device driver itself,
        status = OS_FAILED;
        showWaveError("MpidWinMM::enableDevice", res, -1, __LINE__);
        waveInClose(mDevHandle);
        mDevHandle = NULL; // Open didn't work, reset device handle to NULL
        mWinMMDeviceId = -1; // Make device invalid.

        // and return OS_FAILED.
        return status;
    }

    // Allocate the buffers we are going to use to receive audio data from
    // the windows audio input callback.
    // Calculate the buffer length we're going to use.
    // number of samples per frame * sample size in bytes
    mWaveBufSize = mSamplesPerFrame * sizeof(MpAudioSample);
    unsigned i;
    for (i = 0; i < mNumInBuffers; i++)
    {
        mpWaveBuffers[i] = new char[mWaveBufSize];
    }

    // Setup the buffers so windows can stuff them full of audio
    // when it becomes available from this audio input device.
    WAVEHDR* pWaveHdr = NULL;
    for (i=0; i < mNumInBuffers; i++)
    {
        pWaveHdr = initWaveHeader(i);

        res = waveInPrepareHeader(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInPrepareHeader", res, i, __LINE__);
            waveInClose(mDevHandle);
            mDevHandle = NULL;
            mWinMMDeviceId = -1;

            // and return OS_FAILED.
            return status;
        }
        res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInAddBuffer", res, i, __LINE__);
            waveInClose(mDevHandle);
            mDevHandle = NULL;
            mWinMMDeviceId = -1;

            // and return OS_FAILED.
            return status;
        }
    }

    // Tell windows to start sending audio data to the callback.
    res = waveInStart(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        // If waveInStart failed, print out the error info,
        // invalidate the handle and the device driver itself,
        status = OS_FAILED;
        showWaveError("waveInStart", res, -1, __LINE__);
        waveInClose(mDevHandle);
        mDevHandle = NULL;
        mWinMMDeviceId = -1;

        // and return OS_FAILED.
        return status;
    }

    // If enableDevice failed, return indicating failure.
    if (status == OS_SUCCESS)
    {
        mIsEnabled = TRUE;
    }

    return status;
}

OsStatus MpidWinMM::disableDevice()
{
    OsStatus status = OS_SUCCESS;
    MMRESULT   res;

    if (!isDeviceValid() || !isEnabled())
    {
        return OS_FAILED;
    }

    // Indicate we are no longer enabled -- Do this first,
    // since we'll be partially disabled from here on out.
    // It is very important that this happen *before* waveInReset,
    // as the callback will continue to add and process buffers
    // while waveInReset is called causing a deadlock.
    mIsEnabled = FALSE;

    // Cleanup
    if (mDevHandle == NULL)
    {
        return OS_INVALID_STATE;
    }

    // Reset performs a stop, resets the buffers, and marks them
    // for being sent to the callback.
    // The remaining data in the windows buffers *IS* sent to the callback,
    // So be sure to watch for it and drop it on the floor.
    res = waveInReset(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        showWaveError("waveInReset", res, -1, __LINE__);
    }

    // Must unprepare the headers after a reset, but before the device is closed
    // (if this is done after waveInClose, mDevHandle will be invalid and
    // MMSYSERR_INVALHANDLE will be returned.
    unsigned i;
    for (i=0; i < mNumInBuffers; i++)
    {
        res = waveInUnprepareHeader(mDevHandle, &mpWaveHeaders[i], sizeof(WAVEHDR));
        if (res != MMSYSERR_NOERROR)
        {
            showWaveError("waveInUnprepareHeader", res, i, __LINE__);
        }
    }

    res = waveInClose(mDevHandle);
    if (res != MMSYSERR_NOERROR)
    {
        showWaveError("waveInClose", res, -1, __LINE__);
    }

    // Delete the buffers that were allocated in enableDevice()
    for (i = 0; i < mNumInBuffers; i++)
    {
        delete[] mpWaveBuffers[i];
        mpWaveBuffers[i] = NULL;
    }

    // set the device handle to NULL, since it no longer is valid.
    mDevHandle = NULL;

    // Clear out all the wave header information.
    mSamplesPerFrame = 0;
    mSamplesPerSec = 0;
    mCurrentFrameTime = 0;

    return status;
}

/* ============================ ACCESSORS ================================= */

/* ////////////////////////// PUBLIC STATIC ///////////////////////////////// */
UtlString MpidWinMM::getDefaultDeviceName()
{
   UtlString devName = "";

   // Get windows default input device name
   unsigned nDevs = waveInGetNumDevs();
   if (nDevs == 0)
   {
      OsSysLog::add(FAC_AUDIO, PRI_ERR,
                    "MpidWinMM::getDefaultDeviceName: "
                    "No input audio devices present!");
   }
   assert(nDevs != 0);

   MMRESULT wavResult = MMSYSERR_NOERROR;
   WAVEINCAPS devCaps;
   int defaultWinDeviceId = 0;
   wavResult =
      waveInGetDevCaps(defaultWinDeviceId, &devCaps, sizeof(devCaps));
   if (wavResult != MMSYSERR_NOERROR)
   {
      OsSysLog::add(FAC_AUDIO, PRI_ERR,
                    "MpodWinMM::getDefaultDeviceName: "
                    "Couldn't get default input device capabilities!");
      showWaveError("WINDOWS_DEFAULT_DEVICE_HACK",
                    wavResult, -1, __LINE__);
   }
   else
   {
      devName = devCaps.szPname;
   }
   assert(wavResult == MMSYSERR_NOERROR);
   return devName;
}

/* ============================ INQUIRY =================================== */
/* //////////////////////////// PROTECTED ///////////////////////////////// */

WAVEHDR* MpidWinMM::initWaveHeader(int n)
{
    assert((n >= 0) && (n < (int)mNumInBuffers));
    assert(mpWaveHeaders != NULL);
    assert((mpWaveBuffers != NULL) && (mpWaveBuffers[n] != NULL));
    WAVEHDR* pWave_hdr = &(mpWaveHeaders[n]);

    // zero out the wave buffer.
    memset(mpWaveBuffers[n], 0, mWaveBufSize);

    // Set wave header data to initial values.
    pWave_hdr->lpData = mpWaveBuffers[n];
    pWave_hdr->dwBufferLength = mWaveBufSize;
    pWave_hdr->dwBytesRecorded = 0;  // Filled in by wave functions
    pWave_hdr->dwUser = n;
    pWave_hdr->dwFlags = 0;
    pWave_hdr->dwLoops = 0;
    pWave_hdr->lpNext = NULL;
    pWave_hdr->reserved = 0;

    return pWave_hdr;
}
void MpidWinMM::processAudioInput(HWAVEIN hwi,
                                  UINT uMsg,
                                  void* dwParam1)
{
    if (!mIsOpen)
    {
        assert(uMsg == WIM_OPEN);
        if (uMsg == WIM_OPEN)
        {
//            printf("received WIM_OPEN\n"); fflush(stdout);
            mIsOpen = TRUE;
        }
    }
    if (uMsg == WIM_DATA)
    {
//        printf("received WIM_DATA\n"); fflush(stdout);
        assert(mIsOpen);
        WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1;
        assert(pWaveHdr->dwBufferLength
               == (mSamplesPerFrame*sizeof(MpAudioSample)));
        assert(pWaveHdr->lpData != NULL);

        // Only process if we're enabled..
        if(mIsEnabled)
        {
           mpInputDeviceManager->pushFrame(mDeviceId,
                                           mSamplesPerFrame,
                                           (MpAudioSample*)pWaveHdr->lpData,
                                           mCurrentFrameTime);
           // Ok, we have received and pushed a frame to the manager,
           // Now we advance the frame time.
           mCurrentFrameTime += (mSamplesPerFrame*1000)/mSamplesPerSec;
        }

        if(mIsEnabled)
        {
           // Put the wave header back in the pool..
           MMRESULT res = MMSYSERR_NOERROR;

           res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR));
           if (res != MMSYSERR_NOERROR)
           {
              showWaveError("waveInAddBuffer", res, -1, __LINE__);
              mnAddBufferFailures++;
              if(mnAddBufferFailures >= mNumInBuffers)
              {
                 waveInClose(mDevHandle);
                 mDevHandle = NULL;
                 mWinMMDeviceId = -1;
              }
           }
        }
    }
    else if (uMsg == WIM_CLOSE)
    {
//        printf("received WIM_CLOSE\n"); fflush(stdout);
        mIsOpen = FALSE;
    }
}

void CALLBACK
MpidWinMM::waveInCallbackStatic(HWAVEIN hwi,
                                UINT uMsg,
                                void* dwInstance,
                                void* dwParam1,
                                void* dwParam2)
{
    assert(dwInstance != NULL);
    MpidWinMM* iddWntPtr = (MpidWinMM*)dwInstance;
    assert((uMsg == WIM_OPEN) || (hwi == iddWntPtr->mDevHandle));
    iddWntPtr->processAudioInput(hwi, uMsg, dwParam1);
}

/* //////////////////////////// PRIVATE /////////////////////////////////// */
<|endoftext|>


<commit_before><commit_msg>[fix] use Add for full bit prime (now not used)<commit_after><|endoftext|>


<commit_before><commit_msg>ReadUniStringLine never called without explicit length<commit_after><|endoftext|>


<commit_before><commit_msg>record the ESS before resampling, which is more useful<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: srchdlg.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 22:53:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SFX_SRCHDLG_HXX_
#define _SFX_SRCHDLG_HXX_

#ifndef _VCL_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_COMBOBOX_HXX
#include <vcl/combobox.hxx>
#endif
#ifndef _VCL_EDIT_HXX
#include <vcl/edit.hxx>
#endif
#ifndef _VCL_FIXED_HXX
#include <vcl/fixed.hxx>
#endif

#ifndef _BASEDLGS_HXX
#include <sfx2/basedlgs.hxx>
#endif

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

namespace sfx2 {

// ============================================================================
// SearchDialog
// ============================================================================

class SearchDialog : public ModelessDialog
{
private:
    FixedText           m_aSearchLabel;
    ComboBox            m_aSearchEdit;
    CheckBox            m_aWholeWordsBox;
    CheckBox            m_aMatchCaseBox;
    CheckBox            m_aWrapAroundBox;
    CheckBox            m_aBackwardsBox;
    PushButton          m_aFindBtn;
    CancelButton        m_aCancelBtn;

    Link                m_aFindHdl;
    Link                m_aCloseHdl;

    String              m_sToggleText;
    ::rtl::OUString     m_sConfigName;
    ByteString          m_sWinState;

    bool                m_bIsConstructed;

    void                LoadConfig();
    void                SaveConfig();

    DECL_LINK(          FindHdl, PushButton* );
    DECL_LINK(          ToggleHdl, CheckBox* );

public:
    SearchDialog( Window* pWindow, const ::rtl::OUString& rConfigName );
    ~SearchDialog();

    inline void         SetFindHdl( const Link& rLink ) { m_aFindHdl = rLink; }
    inline void         SetCloseHdl( const Link& rLink ) { m_aCloseHdl = rLink; }

    inline String       GetSearchText() const { return m_aSearchEdit.GetText(); }
    inline void         SetSearchText( const String& _rText ) { m_aSearchEdit.SetText( _rText ); }
    inline bool         IsOnlyWholeWords() const { return ( m_aWholeWordsBox.IsChecked() != FALSE ); }
    inline bool         IsMarchCase() const { return ( m_aMatchCaseBox.IsChecked() != FALSE ); }
    inline bool         IsWrapAround() const { return ( m_aWrapAroundBox.IsChecked() != FALSE ); }
    inline bool         IsSearchBackwards() const { return ( m_aBackwardsBox.IsChecked() != FALSE ); }

    void                SetFocusOnEdit();

    virtual BOOL        Close();
    virtual void        Move();
    virtual void        StateChanged( StateChangedType nStateChange );
};

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

} // namespace sfx2

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

#endif // _SFX_SRCHDLG_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.4.216); FILE MERGED 2008/04/01 15:38:17 thb 1.4.216.3: #i85898# Stripping all external header guards 2008/04/01 12:40:33 thb 1.4.216.2: #i85898# Stripping all external header guards 2008/03/31 13:37:54 rt 1.4.216.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: srchdlg.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _SFX_SRCHDLG_HXX_
#define _SFX_SRCHDLG_HXX_

#ifndef _VCL_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#include <vcl/combobox.hxx>
#ifndef _VCL_EDIT_HXX
#include <vcl/edit.hxx>
#endif
#ifndef _VCL_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#include <sfx2/basedlgs.hxx>

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

namespace sfx2 {

// ============================================================================
// SearchDialog
// ============================================================================

class SearchDialog : public ModelessDialog
{
private:
    FixedText           m_aSearchLabel;
    ComboBox            m_aSearchEdit;
    CheckBox            m_aWholeWordsBox;
    CheckBox            m_aMatchCaseBox;
    CheckBox            m_aWrapAroundBox;
    CheckBox            m_aBackwardsBox;
    PushButton          m_aFindBtn;
    CancelButton        m_aCancelBtn;

    Link                m_aFindHdl;
    Link                m_aCloseHdl;

    String              m_sToggleText;
    ::rtl::OUString     m_sConfigName;
    ByteString          m_sWinState;

    bool                m_bIsConstructed;

    void                LoadConfig();
    void                SaveConfig();

    DECL_LINK(          FindHdl, PushButton* );
    DECL_LINK(          ToggleHdl, CheckBox* );

public:
    SearchDialog( Window* pWindow, const ::rtl::OUString& rConfigName );
    ~SearchDialog();

    inline void         SetFindHdl( const Link& rLink ) { m_aFindHdl = rLink; }
    inline void         SetCloseHdl( const Link& rLink ) { m_aCloseHdl = rLink; }

    inline String       GetSearchText() const { return m_aSearchEdit.GetText(); }
    inline void         SetSearchText( const String& _rText ) { m_aSearchEdit.SetText( _rText ); }
    inline bool         IsOnlyWholeWords() const { return ( m_aWholeWordsBox.IsChecked() != FALSE ); }
    inline bool         IsMarchCase() const { return ( m_aMatchCaseBox.IsChecked() != FALSE ); }
    inline bool         IsWrapAround() const { return ( m_aWrapAroundBox.IsChecked() != FALSE ); }
    inline bool         IsSearchBackwards() const { return ( m_aBackwardsBox.IsChecked() != FALSE ); }

    void                SetFocusOnEdit();

    virtual BOOL        Close();
    virtual void        Move();
    virtual void        StateChanged( StateChangedType nStateChange );
};

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

} // namespace sfx2

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

#endif // _SFX_SRCHDLG_HXX_

<|endoftext|>


<commit_before>//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>

using llvm::object::Archive;
using llvm::object::ObjectFile;
using llvm::object::SymbolRef;
using llvm::object::symbol_iterator;
using llvm::object::object_error;

namespace lld {

namespace {

/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
              StringRef path, bool logLoading)
      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
        _registry(reg), _logLoading(logLoading) {}

  /// \brief Check if any member of the archive contains an Atom with the
  /// specified name and return the File object for that member, or nullptr.
  File *find(StringRef name, bool dataSymbolOnly) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return nullptr;
    Archive::child_iterator ci = member->second;

    // Don't return a member already returned
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return nullptr;
    if (dataSymbolOnly && !isDataSymbol(ci, name))
      return nullptr;

    _membersInstantiated.insert(memberStart);

    // Check if a file is preloaded.
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _preloaded.find(memberStart);
      if (it != _preloaded.end()) {
        std::unique_ptr<Future<File *>> &p = it->second;
        Future<File *> *future = p.get();
        return future->get();
      }
    }

    std::unique_ptr<File> result;
    if (instantiateMember(ci, result))
      return nullptr;

    // give up the pointer so that this object no longer manages it
    return result.release();
  }

  // Instantiate a member file containing a given symbol name.
  void preload(TaskGroup &group, StringRef name) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return;
    Archive::child_iterator ci = member->second;

    // Do nothing if a member is already instantiated.
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return;

    std::lock_guard<std::mutex> lock(_mutex);
    if (_preloaded.find(memberStart) != _preloaded.end())
      return;

    // Instantiate the member
    auto *future = new Future<File *>();
    _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);

    group.spawn([=] {
      std::unique_ptr<File> result;
      std::error_code ec = instantiateMember(ci, result);
      future->set(ec ? nullptr : result.release());
    });
  }

  /// \brief parse each member
  std::error_code
  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
    if (std::error_code ec = parse())
      return ec;
    for (auto mf = _archive->child_begin(), me = _archive->child_end();
         mf != me; ++mf) {
      std::unique_ptr<File> file;
      if (std::error_code ec = instantiateMember(mf, file))
        return ec;
      result.push_back(std::move(file));
    }
    return std::error_code();
  }

  const AtomVector<DefinedAtom> &defined() const override {
    return _noDefinedAtoms;
  }

  const AtomVector<UndefinedAtom> &undefined() const override {
    return _noUndefinedAtoms;
  }

  const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
    return _noSharedLibraryAtoms;
  }

  const AtomVector<AbsoluteAtom> &absolute() const override {
    return _noAbsoluteAtoms;
  }

  /// Returns a set of all defined symbols in the archive.
  std::set<StringRef> getDefinedSymbols() override {
    parse();
    std::set<StringRef> ret;
    for (const auto &e : _symbolMemberMap)
      ret.insert(e.first);
    return ret;
  }

protected:
  std::error_code doParse() override {
    // Make Archive object which will be owned by FileArchive object.
    std::error_code ec;
    _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
    if (ec)
      return ec;
    if ((ec = buildTableOfContents()))
      return ec;
    return std::error_code();
  }

private:
  std::error_code
  instantiateMember(Archive::child_iterator member,
                    std::unique_ptr<File> &result) const {
    ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
    if (std::error_code ec = mbOrErr.getError())
      return ec;
    llvm::MemoryBufferRef mb = mbOrErr.get();
    std::string memberPath = (_archive->getFileName() + "("
                           + mb.getBufferIdentifier() + ")").str();

    if (_logLoading)
      llvm::errs() << memberPath << "\n";

    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
        mb.getBuffer(), mb.getBufferIdentifier(), false));

    ErrorOr<std::unique_ptr<File>> fileOrErr =
        _registry.loadFile(std::move(memberMB));
    if (std::error_code ec = fileOrErr.getError())
      return ec;
    result = std::move(fileOrErr.get());
    if (std::error_code ec = result->parse())
      return ec;
    result->setArchivePath(_archive->getFileName());

    // The memory buffer is co-owned by the archive file and the children,
    // so that the bufffer is deallocated when all the members are destructed.
    result->setSharedMemoryBuffer(_mb);
    return std::error_code();
  }

  // Parses the given memory buffer as an object file, and returns true
  // code if the given symbol is a data symbol. If the symbol is not a data
  // symbol or does not exist, returns false.
  bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
    ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
    if (buf.getError())
      return false;
    std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
        buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));

    auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
    if (objOrErr.getError())
      return false;
    std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());

    for (SymbolRef sym : obj->symbols()) {
      // Skip until we find the symbol.
      ErrorOr<StringRef> name = sym.getName();
      if (!name)
        return false;
      if (*name != symbol)
        continue;
      uint32_t flags = sym.getFlags();
      if (flags <= SymbolRef::SF_Undefined)
        continue;

      // Returns true if it's a data symbol.
      SymbolRef::Type type = sym.getType();
      if (type == SymbolRef::ST_Data)
        return true;
    }
    return false;
  }

  std::error_code buildTableOfContents() {
    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
                                       << "Table of contents for archive '"
                                       << _archive->getFileName() << "':\n");
    for (const Archive::Symbol &sym : _archive->symbols()) {
      StringRef name = sym.getName();
      ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
      if (std::error_code ec = memberOrErr.getError())
        return ec;
      Archive::child_iterator member = memberOrErr.get();
      DEBUG_WITH_TYPE(
          "FileArchive",
          llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
                       << "'" << name << "'\n");
      _symbolMemberMap[name] = member;
    }
    return std::error_code();
  }

  typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
  typedef std::set<const char *> InstantiatedSet;

  std::shared_ptr<MemoryBuffer> _mb;
  const Registry &_registry;
  std::unique_ptr<Archive> _archive;
  MemberMap _symbolMemberMap;
  InstantiatedSet _membersInstantiated;
  bool _logLoading;
  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
  std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
  std::mutex _mutex;
};

class ArchiveReader : public Reader {
public:
  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}

  bool canParse(file_magic magic, MemoryBufferRef) const override {
    return magic == llvm::sys::fs::file_magic::archive;
  }

  ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
                                          const Registry &reg) const override {
    StringRef path = mb->getBufferIdentifier();
    std::unique_ptr<File> ret =
        llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
    return std::move(ret);
  }

private:
  bool _logLoading;
};

} // anonymous namespace

void Registry::addSupportArchives(bool logLoading) {
  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
}

} // end namespace lld
<commit_msg>Update for upcoming llvm change.<commit_after>//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Parallel.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>

using llvm::object::Archive;
using llvm::object::ObjectFile;
using llvm::object::SymbolRef;
using llvm::object::symbol_iterator;
using llvm::object::object_error;

namespace lld {

namespace {

/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public lld::ArchiveLibraryFile {
public:
  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
              StringRef path, bool logLoading)
      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
        _registry(reg), _logLoading(logLoading) {}

  /// \brief Check if any member of the archive contains an Atom with the
  /// specified name and return the File object for that member, or nullptr.
  File *find(StringRef name, bool dataSymbolOnly) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return nullptr;
    Archive::child_iterator ci = member->second;

    // Don't return a member already returned
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return nullptr;
    if (dataSymbolOnly && !isDataSymbol(ci, name))
      return nullptr;

    _membersInstantiated.insert(memberStart);

    // Check if a file is preloaded.
    {
      std::lock_guard<std::mutex> lock(_mutex);
      auto it = _preloaded.find(memberStart);
      if (it != _preloaded.end()) {
        std::unique_ptr<Future<File *>> &p = it->second;
        Future<File *> *future = p.get();
        return future->get();
      }
    }

    std::unique_ptr<File> result;
    if (instantiateMember(ci, result))
      return nullptr;

    // give up the pointer so that this object no longer manages it
    return result.release();
  }

  // Instantiate a member file containing a given symbol name.
  void preload(TaskGroup &group, StringRef name) override {
    auto member = _symbolMemberMap.find(name);
    if (member == _symbolMemberMap.end())
      return;
    Archive::child_iterator ci = member->second;

    // Do nothing if a member is already instantiated.
    const char *memberStart = ci->getBuffer().data();
    if (_membersInstantiated.count(memberStart))
      return;

    std::lock_guard<std::mutex> lock(_mutex);
    if (_preloaded.find(memberStart) != _preloaded.end())
      return;

    // Instantiate the member
    auto *future = new Future<File *>();
    _preloaded[memberStart] = std::unique_ptr<Future<File *>>(future);

    group.spawn([=] {
      std::unique_ptr<File> result;
      std::error_code ec = instantiateMember(ci, result);
      future->set(ec ? nullptr : result.release());
    });
  }

  /// \brief parse each member
  std::error_code
  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
    if (std::error_code ec = parse())
      return ec;
    for (auto mf = _archive->child_begin(), me = _archive->child_end();
         mf != me; ++mf) {
      std::unique_ptr<File> file;
      if (std::error_code ec = instantiateMember(mf, file))
        return ec;
      result.push_back(std::move(file));
    }
    return std::error_code();
  }

  const AtomVector<DefinedAtom> &defined() const override {
    return _noDefinedAtoms;
  }

  const AtomVector<UndefinedAtom> &undefined() const override {
    return _noUndefinedAtoms;
  }

  const AtomVector<SharedLibraryAtom> &sharedLibrary() const override {
    return _noSharedLibraryAtoms;
  }

  const AtomVector<AbsoluteAtom> &absolute() const override {
    return _noAbsoluteAtoms;
  }

  /// Returns a set of all defined symbols in the archive.
  std::set<StringRef> getDefinedSymbols() override {
    parse();
    std::set<StringRef> ret;
    for (const auto &e : _symbolMemberMap)
      ret.insert(e.first);
    return ret;
  }

protected:
  std::error_code doParse() override {
    // Make Archive object which will be owned by FileArchive object.
    std::error_code ec;
    _archive.reset(new Archive(_mb->getMemBufferRef(), ec));
    if (ec)
      return ec;
    if ((ec = buildTableOfContents()))
      return ec;
    return std::error_code();
  }

private:
  std::error_code
  instantiateMember(Archive::child_iterator member,
                    std::unique_ptr<File> &result) const {
    ErrorOr<llvm::MemoryBufferRef> mbOrErr = member->getMemoryBufferRef();
    if (std::error_code ec = mbOrErr.getError())
      return ec;
    llvm::MemoryBufferRef mb = mbOrErr.get();
    std::string memberPath = (_archive->getFileName() + "("
                           + mb.getBufferIdentifier() + ")").str();

    if (_logLoading)
      llvm::errs() << memberPath << "\n";

    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
        mb.getBuffer(), mb.getBufferIdentifier(), false));

    ErrorOr<std::unique_ptr<File>> fileOrErr =
        _registry.loadFile(std::move(memberMB));
    if (std::error_code ec = fileOrErr.getError())
      return ec;
    result = std::move(fileOrErr.get());
    if (std::error_code ec = result->parse())
      return ec;
    result->setArchivePath(_archive->getFileName());

    // The memory buffer is co-owned by the archive file and the children,
    // so that the bufffer is deallocated when all the members are destructed.
    result->setSharedMemoryBuffer(_mb);
    return std::error_code();
  }

  // Parses the given memory buffer as an object file, and returns true
  // code if the given symbol is a data symbol. If the symbol is not a data
  // symbol or does not exist, returns false.
  bool isDataSymbol(Archive::child_iterator member, StringRef symbol) const {
    ErrorOr<llvm::MemoryBufferRef> buf = member->getMemoryBufferRef();
    if (buf.getError())
      return false;
    std::unique_ptr<MemoryBuffer> mb(MemoryBuffer::getMemBuffer(
        buf.get().getBuffer(), buf.get().getBufferIdentifier(), false));

    auto objOrErr(ObjectFile::createObjectFile(mb->getMemBufferRef()));
    if (objOrErr.getError())
      return false;
    std::unique_ptr<ObjectFile> obj = std::move(objOrErr.get());

    for (SymbolRef sym : obj->symbols()) {
      // Skip until we find the symbol.
      ErrorOr<StringRef> name = sym.getName();
      if (!name)
        return false;
      if (*name != symbol)
        continue;
      uint32_t flags = sym.getFlags();
      if (flags <= SymbolRef::SF_Undefined)
        continue;

      // Returns true if it's a data symbol.
      SymbolRef::Type type = sym.getType();
      if (type == SymbolRef::ST_Data)
        return true;
    }
    return false;
  }

  std::error_code buildTableOfContents() {
    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
                                       << "Table of contents for archive '"
                                       << _archive->getFileName() << "':\n");
    for (const Archive::Symbol &sym : _archive->symbols()) {
      StringRef name = sym.getName();
      ErrorOr<Archive::child_iterator> memberOrErr = sym.getMember();
      if (std::error_code ec = memberOrErr.getError())
        return ec;
      Archive::child_iterator member = memberOrErr.get();
      DEBUG_WITH_TYPE(
          "FileArchive",
          llvm::dbgs() << llvm::format("0x%08llX ", member->getBuffer().data())
                       << "'" << name << "'\n");
      _symbolMemberMap.insert(std::make_pair(name, member));
    }
    return std::error_code();
  }

  typedef std::unordered_map<StringRef, Archive::child_iterator> MemberMap;
  typedef std::set<const char *> InstantiatedSet;

  std::shared_ptr<MemoryBuffer> _mb;
  const Registry &_registry;
  std::unique_ptr<Archive> _archive;
  MemberMap _symbolMemberMap;
  InstantiatedSet _membersInstantiated;
  bool _logLoading;
  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
  std::map<const char *, std::unique_ptr<Future<File *>>> _preloaded;
  std::mutex _mutex;
};

class ArchiveReader : public Reader {
public:
  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}

  bool canParse(file_magic magic, MemoryBufferRef) const override {
    return magic == llvm::sys::fs::file_magic::archive;
  }

  ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
                                          const Registry &reg) const override {
    StringRef path = mb->getBufferIdentifier();
    std::unique_ptr<File> ret =
        llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
    return std::move(ret);
  }

private:
  bool _logLoading;
};

} // anonymous namespace

void Registry::addSupportArchives(bool logLoading) {
  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
}

} // end namespace lld
<|endoftext|>


<commit_before>#include "hecl/Runtime.hpp"

#include "hecl/hecl.hpp"

#include <logvisor/logvisor.hpp>

#if _WIN32
#include <ShlObj.h>
#endif

#if WINDOWS_STORE
using namespace Windows::Storage;
#endif

namespace hecl::Runtime {
static logvisor::Module Log("FileStoreManager");

FileStoreManager::FileStoreManager(SystemStringView domain) : m_domain(domain) {
#if _WIN32
#if !WINDOWS_STORE
  WCHAR home[MAX_PATH];
  if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, home)))
    Log.report(logvisor::Fatal, fmt(_SYS_STR("unable to locate profile for file store")));

  SystemString path(home);
#else
  StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
  SystemString path(cacheFolder->Path->Data());
#endif
  path += _SYS_STR("/.heclrun");

  hecl::MakeDir(path.c_str());
  path += _SYS_STR('/');
  path += domain.data();

  hecl::MakeDir(path.c_str());
  m_storeRoot = path;
#else
  const char* xdg_data_home = getenv("XDG_DATA_HOME");
  std::string path;
  if (xdg_data_home) {
    if (xdg_data_home[0] != '/')
      Log.report(logvisor::Fatal, fmt("invalid $XDG_DATA_HOME for file store (must be absolute)"));
    path = xdg_data_home;
  } else {
    const char* home = getenv("HOME");
    if (!home)
      Log.report(logvisor::Fatal, fmt("unable to locate $HOME for file store"));
    path = home;
    path += "/.local/share"
  }
  path += "/hecl";
  if (mkdir(path.c_str(), 0755) && errno != EEXIST)
    Log.report(logvisor::Fatal, fmt("unable to mkdir at {}"), path);
  path += '/';
  path += domain.data();
  if (mkdir(path.c_str(), 0755) && errno != EEXIST)
    Log.report(logvisor::Fatal, fmt("unable to mkdir at {}"), path);
  m_storeRoot = path;
#endif
}

} // namespace hecl::Runtime
<commit_msg>Compile fix<commit_after>#include "hecl/Runtime.hpp"

#include "hecl/hecl.hpp"

#include <logvisor/logvisor.hpp>

#if _WIN32
#include <ShlObj.h>
#endif

#if WINDOWS_STORE
using namespace Windows::Storage;
#endif

namespace hecl::Runtime {
static logvisor::Module Log("FileStoreManager");

FileStoreManager::FileStoreManager(SystemStringView domain) : m_domain(domain) {
#if _WIN32
#if !WINDOWS_STORE
  WCHAR home[MAX_PATH];
  if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, home)))
    Log.report(logvisor::Fatal, fmt(_SYS_STR("unable to locate profile for file store")));

  SystemString path(home);
#else
  StorageFolder ^ cacheFolder = ApplicationData::Current->LocalCacheFolder;
  SystemString path(cacheFolder->Path->Data());
#endif
  path += _SYS_STR("/.heclrun");

  hecl::MakeDir(path.c_str());
  path += _SYS_STR('/');
  path += domain.data();

  hecl::MakeDir(path.c_str());
  m_storeRoot = path;
#else
  const char* xdg_data_home = getenv("XDG_DATA_HOME");
  std::string path;
  if (xdg_data_home) {
    if (xdg_data_home[0] != '/')
      Log.report(logvisor::Fatal, fmt("invalid $XDG_DATA_HOME for file store (must be absolute)"));
    path = xdg_data_home;
  } else {
    const char* home = getenv("HOME");
    if (!home)
      Log.report(logvisor::Fatal, fmt("unable to locate $HOME for file store"));
    path = home;
    path += "/.local/share";
  }
  path += "/hecl";
  if (mkdir(path.c_str(), 0755) && errno != EEXIST)
    Log.report(logvisor::Fatal, fmt("unable to mkdir at {}"), path);
  path += '/';
  path += domain.data();
  if (mkdir(path.c_str(), 0755) && errno != EEXIST)
    Log.report(logvisor::Fatal, fmt("unable to mkdir at {}"), path);
  m_storeRoot = path;
#endif
}

} // namespace hecl::Runtime
<|endoftext|>


<commit_before><commit_msg>Updated GMM training seed in mex wrapper to be different each run<commit_after><|endoftext|>