<commit_before>//===--- DebugTypeInfo.h - Type Info for Debugging --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the data structure that holds all the debug info
// we want to emit for types.
//
//===----------------------------------------------------------------------===//

#include "DebugTypeInfo.h"
#include "IRGen.h"
#include "FixedTypeInfo.h"

using namespace swift;
using namespace irgen;

DebugTypeInfo::DebugTypeInfo(Type Ty, uint64_t Size, uint64_t Align)
  : Ty(Ty), SizeInBytes(Size), AlignmentInBytes(Align) {
}

DebugTypeInfo::DebugTypeInfo(Type Ty, Size Size, Alignment Align)
  : Ty(Ty), SizeInBytes(Size.getValue()), AlignmentInBytes(Align.getValue()) {
}

DebugTypeInfo::DebugTypeInfo(Type Ty, const TypeInfo &Info)
  : Ty(Ty) {
  if (Info.isFixedSize()) {
    const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
    SizeInBytes = FixTy.getFixedSize().getValue();
    AlignmentInBytes = FixTy.getBestKnownAlignment().getValue();
  }
}

DebugTypeInfo::DebugTypeInfo(const ValueDecl &Decl, const TypeInfo &Info)
  : Ty(Decl.getType()) {
  // Same as above.
  if (Info.isFixedSize()) {
    const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
    SizeInBytes = FixTy.getFixedSize().getValue();
    AlignmentInBytes = FixTy.getBestKnownAlignment().getValue();
  }
}

DebugTypeInfo::DebugTypeInfo(const ValueDecl &Decl, Size Size, Alignment Align)
  : Ty(Decl.getType()),
    SizeInBytes(Size.getValue()),
    AlignmentInBytes(Align.getValue()) {
}

bool DebugTypeInfo::operator==(DebugTypeInfo T) const {
  bool TypesEqual;
  if (Ty.getPointer() == T.Ty.getPointer())
    TypesEqual = true;
  else {
    // nullptr.
    if (Ty.isNull() || T.Ty.isNull())
      TypesEqual = false;

    // Tombstone.
    auto Tombstone =
      llvm::DenseMapInfo<swift::Type>::getTombstoneKey().getPointer();
    if ((Ty.getPointer() == Tombstone) || (T.Ty.getPointer() == Tombstone))
      TypesEqual = false;

    // Pointers are safe, do the real comparison.
    if (TypesEqual)
      TypesEqual = Ty->isSpelledLike(T.Ty.getPointer());
  }

  return TypesEqual
    && SizeInBytes == T.SizeInBytes
    && AlignmentInBytes == T.AlignmentInBytes;
}

bool DebugTypeInfo::operator!=(DebugTypeInfo T) const {
  return !operator==(T);
}
<commit_msg>Rewrite type comparison logic to use early exits.<commit_after>//===--- DebugTypeInfo.h - Type Info for Debugging --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the data structure that holds all the debug info
// we want to emit for types.
//
//===----------------------------------------------------------------------===//

#include "DebugTypeInfo.h"
#include "IRGen.h"
#include "FixedTypeInfo.h"

using namespace swift;
using namespace irgen;

DebugTypeInfo::DebugTypeInfo(Type Ty, uint64_t Size, uint64_t Align)
  : Ty(Ty), SizeInBytes(Size), AlignmentInBytes(Align) {
}

DebugTypeInfo::DebugTypeInfo(Type Ty, Size Size, Alignment Align)
  : Ty(Ty), SizeInBytes(Size.getValue()), AlignmentInBytes(Align.getValue()) {
}

DebugTypeInfo::DebugTypeInfo(Type Ty, const TypeInfo &Info)
  : Ty(Ty) {
  if (Info.isFixedSize()) {
    const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
    SizeInBytes = FixTy.getFixedSize().getValue();
    AlignmentInBytes = FixTy.getBestKnownAlignment().getValue();
  }
}

DebugTypeInfo::DebugTypeInfo(const ValueDecl &Decl, const TypeInfo &Info)
  : Ty(Decl.getType()) {
  // Same as above.
  if (Info.isFixedSize()) {
    const FixedTypeInfo &FixTy = *cast<const FixedTypeInfo>(&Info);
    SizeInBytes = FixTy.getFixedSize().getValue();
    AlignmentInBytes = FixTy.getBestKnownAlignment().getValue();
  }
}

DebugTypeInfo::DebugTypeInfo(const ValueDecl &Decl, Size Size, Alignment Align)
  : Ty(Decl.getType()),
    SizeInBytes(Size.getValue()),
    AlignmentInBytes(Align.getValue()) {
}

static bool typesEqual(Type A, Type B) {
  if (A.getPointer() == B.getPointer())
    return true;

  // nullptr.
  if (A.isNull() || B.isNull())
    return false;

  // Tombstone.
  auto Tombstone =
    llvm::DenseMapInfo<swift::Type>::getTombstoneKey().getPointer();
  if ((A.getPointer() == Tombstone) || (B.getPointer() == Tombstone))
    return false;

  // Pointers are safe, do the real comparison.
  return A->isSpelledLike(B.getPointer());
}

bool DebugTypeInfo::operator==(DebugTypeInfo T) const {
  return typesEqual(Ty, T.Ty)
    && SizeInBytes == T.SizeInBytes
    && AlignmentInBytes == T.AlignmentInBytes;
}

bool DebugTypeInfo::operator!=(DebugTypeInfo T) const {
  return !operator==(T);
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Spotify AB
//
// 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 <stdio.h>
#include <string>
#include <boost/python.hpp>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

using namespace std;
using namespace boost;

template<typename T>
struct __attribute__((__packed__)) node {
  /*
   * We store a binary tree where each node has two things
   * - A vector associated with it
   * - Two children
   * All nodes occupy the same amount of memory
   * All nodes with n_descendants == 1 are leaf nodes.
   * A memory optimization is that for nodes with 2 <= n_descendants <= K,
   * we skip the vector. Instead we store a list of all descendants. K is
   * determined by the number of items that fits in the same space.
   * For nodes with n_descendants == 1 or > K, there is always a
   * corresponding vector.
   * Note that we can't really do sizeof(node<T>) because we cheat and allocate
   * more memory to be able to fit the vector outside
   */
  int n_descendants;
  int children[2]; // Will possibly store more than 2
  T v[0]; // Hack. We just allocate as much memory as we need and let this array overflow
};

template<typename T>
class AnnoyIndex {
  /*
   * We use random projection to build a forest of binary trees of all items.
   * Basically just split the hyperspace into two sides by a hyperplane,
   * then recursively split each of those subtrees etc.
   * We create a tree like this q times. The default q is determined automatically
   * in such a way that we at most use 2x as much memory as the vectors take.
   */
  int _f;
  size_t _s;
  int _n_items;
  mt19937 _rng;
  normal_distribution<T> _nd;
  variate_generator<mt19937&,
		    normal_distribution<T> > _var_nor;
  void* _nodes; // Could either be mmapped, or point to a memory buffer that we reallocate
  int _n_nodes;
  int _nodes_size;
  vector<int> _roots;
  int _K;
  bool _loaded;
public:
  AnnoyIndex(int f) : _rng(), _nd(), _var_nor(_rng, _nd) {
    _f = f;
    _s = sizeof(node<T>) + sizeof(T) * f; // Size of each node
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _loaded = false;

    _K = (sizeof(T) * f + sizeof(int) * 2) / sizeof(int);
  }
  ~AnnoyIndex() {
    if (!_loaded && _nodes) {
      free(_nodes);
    }
  }

  void add_item(int item, const python::list& v) {
    _allocate_size(item+1);
    node<T>* n = _get(item);

    n->children[0] = 0;
    n->children[1] = 0;
    n->n_descendants = 1;

    for (int z = 0; z < _f; z++)
      n->v[z] = python::extract<T>(v[z]);

    if (item >= _n_items)
      _n_items = item + 1;
  }

  void build(int q) {
    _n_nodes = _n_items;
    while (1) {
      if (q == -1 && _n_nodes >= _n_items * 2)
	break;
      if (q != -1 && _roots.size() >= (size_t)q)
	break;
      printf("pass %zd...\n", _roots.size());

      vector<int> indices;
      for (int i = 0; i < _n_items; i++)
	indices.push_back(i);

      _roots.push_back(_make_tree(indices));
    }
    // Also, copy the roots into the last segment of the array
    // This way we can load them faster without reading the whole file
    _allocate_size(_n_nodes + _roots.size());
    for (size_t i = 0; i < _roots.size(); i++)
      memcpy(_get(_n_nodes + i), _get(_roots[i]), _s);
    _n_nodes += _roots.size();

    printf("has %d nodes\n", _n_nodes);
  }

  void save(const string& filename) {
    FILE *f = fopen(filename.c_str(), "w");

    fwrite(_nodes, _s, _n_nodes, f);

    fclose(f);

    free(_nodes);
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _roots.clear();
    load(filename);
  }

  void load(const string& filename) {
    struct stat buf;
    stat(filename.c_str(), &buf);
    off_t size = buf.st_size;
    int fd = open(filename.c_str(), O_RDONLY, (mode_t)0400);
    _nodes = (node<T>*)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);

    _n_nodes = size / _s;

    // Find the roots by scanning the end of the file and taking the nodes with most descendants
    int m = -1;
    for (int i = _n_nodes - 1; i >= 0; i--) {
      int k = _get(i)->n_descendants;
      if (m == -1 || k == m) {
	_roots.push_back(i);
	m = k;
      } else {
	break;
      }
    }
    _loaded = true;
    _n_items = m;
    printf("found %lu roots with degree %d\n", _roots.size(), m);
  }

  inline T _cos(const T* x, const T* y) {
    T pp = 0, qq = 0, pq = 0;
    for (int z = 0; z < _f; z++) {
      pp += x[z] * x[z];
      qq += y[z] * y[z];
      pq += x[z] * y[z];
    }
    T ppqq = pp * qq;
    if (ppqq > 0) return pq / sqrt(ppqq);
    else return 0.0;
  }

  inline T cos(int i, int j) {
    const T* x = _get(i)->v;
    const T* y = _get(j)->v;
    return _cos(x, y);
  }

  python::list get_nns_by_item(int item, int n) {
    const node<T>* m = _get(item);
    return _get_all_nns(m->v, n);
  }
  python::list get_nns_by_vector(python::list v, int n) {
    vector<T> w(_f);
    for (int z = 0; z < _f; z++)
      w[z] = python::extract<T>(v[z]);
    return _get_all_nns(&w[0], n);
  }

  int get_n_items() {
    return _n_items;
  }
private:
  void _allocate_size(int n) {
    if (n > _nodes_size) {
      int new_nodes_size = (_nodes_size + 1) * 2;
      if (n > new_nodes_size)
	new_nodes_size = n;
      _nodes = realloc(_nodes, _s * new_nodes_size);
      memset((char *)_nodes + (_nodes_size * _s)/sizeof(char), 0, (new_nodes_size - _nodes_size) * _s);
      _nodes_size = new_nodes_size;
    }
  }

  inline node<T>* _get(int i) {
    return (node<T>*)((char *)_nodes + (_s * i)/sizeof(char));
  }

  int _make_tree(const vector<int >& indices) {
    if (indices.size() == 1)
      return indices[0];

    _allocate_size(_n_nodes + 1);
    int item = _n_nodes++;
    node<T>* m = _get(item);
    m->n_descendants = indices.size();

    if (indices.size() <= (size_t)_K) {
      for (size_t i = 0; i < indices.size(); i++)
	m->children[i] = indices[i];
      return item;
    }

    vector<int> children_indices[2];
    for (int attempt = 0; attempt < 20; attempt ++) {
      /*
       * Create a random hyperplane.
       * If all points end up on the same time, we try again.
       * We could in principle *construct* a plane so that we split
       * all items evenly, but I think that could violate the guarantees
       * given by just picking a hyperplane at random
       */
      for (int z = 0; z < _f; z++)
	m->v[z] = _var_nor();

      children_indices[0].clear();
      children_indices[1].clear();

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	node<T>* n = _get(j);
	if (!n) {
	  printf("node %d undef...\n", j);
	  continue;
	}
	T dot = 0;
	for (int z = 0; z < _f; z++) {
	  dot += m->v[z] * n->v[z];
	}
	while (dot == 0)
	  dot = _var_nor();
	children_indices[dot > 0].push_back(j);
      }

      if (children_indices[0].size() > 0 && children_indices[1].size() > 0) {
	break;
      }
    }

    while (children_indices[0].size() == 0 || children_indices[1].size() == 0) {
      // If we didn't find a hyperplane, just randomize sides as a last option
      if (indices.size() > 100000)
	printf("Failed splitting %lu items\n", indices.size());

      children_indices[0].clear();
      children_indices[1].clear();

      // Set the vector to 0.0
      for (int z = 0; z < _f; z++)
	m->v[z] = 0.0;

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	// Just randomize...
	children_indices[_var_nor() > 0].push_back(j);
      }
    }

    int children_0 = _make_tree(children_indices[0]);
    int children_1 = _make_tree(children_indices[1]);

    // We need to fetch m again because it might have been reallocated
    m = _get(item);
    m->children[0] = children_0;
    m->children[1] = children_1;

    return item;
  }

  void _get_nns(const T* v, int i, vector<int>* result, int limit) {
    const node<T>* n = _get(i);

    if (n->n_descendants == 0) {
      // unknown item, nothing to do...
    } else if (n->n_descendants == 1) {
      result->push_back(i);
    } else if (n->n_descendants <= _K) {
      for (int j = 0; j < n->n_descendants; j++) {
	result->push_back(n->children[j]);
      }
    } else {
      T dot = 0;

      for (int z = 0; z < _f; z++)
	dot += v[z] * n->v[z];

      while (dot == 0) // Randomize side if the dot product is zero
	dot = _var_nor();

      _get_nns(v, n->children[dot > 0], result, limit);
      if (result->size() < (size_t)limit)
	_get_nns(v, n->children[dot < 0], result, limit);
    }
  }

  python::list _get_all_nns(const T* v, int n) {
    vector<pair<T, int> > nns_cos;

    for (size_t i = 0; i < _roots.size(); i++) {
      vector<int> nns;
      _get_nns(v, _roots[i], &nns, n);
      for (size_t j = 0; j < nns.size(); j++) {
	nns_cos.push_back(make_pair(_cos(v, _get(nns[j])->v), nns[j]));
      }
    }
    sort(nns_cos.begin(), nns_cos.end());
    int last = -1, length=0;
    python::list l;
    for (int i = (int)nns_cos.size() - 1; i >= 0 && length < n; i--) {
      if (nns_cos[i].second != last) {
	l.append(nns_cos[i].second);
	last = nns_cos[i].second;
	length++;
      }
    }
    return l;
  }
};

BOOST_PYTHON_MODULE(annoylib)
{
  python::class_<AnnoyIndex<float> >("AnnoyIndex", python::init<int>())
    .def("add_item",          &AnnoyIndex<float>::add_item)
    .def("build",             &AnnoyIndex<float>::build)
    .def("save",              &AnnoyIndex<float>::save)
    .def("load",              &AnnoyIndex<float>::load)
    .def("cos",               &AnnoyIndex<float>::cos)
    .def("get_nns_by_item",   &AnnoyIndex<float>::get_nns_by_item)
    .def("get_nns_by_vector", &AnnoyIndex<float>::get_nns_by_vector)
    .def("get_n_items",       &AnnoyIndex<float>::get_n_items);
}
<commit_msg>changed name of cos to get_cos<commit_after>// Copyright (c) 2013 Spotify AB
//
// 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 <stdio.h>
#include <string>
#include <boost/python.hpp>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

using namespace std;
using namespace boost;

template<typename T>
struct __attribute__((__packed__)) node {
  /*
   * We store a binary tree where each node has two things
   * - A vector associated with it
   * - Two children
   * All nodes occupy the same amount of memory
   * All nodes with n_descendants == 1 are leaf nodes.
   * A memory optimization is that for nodes with 2 <= n_descendants <= K,
   * we skip the vector. Instead we store a list of all descendants. K is
   * determined by the number of items that fits in the same space.
   * For nodes with n_descendants == 1 or > K, there is always a
   * corresponding vector.
   * Note that we can't really do sizeof(node<T>) because we cheat and allocate
   * more memory to be able to fit the vector outside
   */
  int n_descendants;
  int children[2]; // Will possibly store more than 2
  T v[0]; // Hack. We just allocate as much memory as we need and let this array overflow
};

template<typename T>
class AnnoyIndex {
  /*
   * We use random projection to build a forest of binary trees of all items.
   * Basically just split the hyperspace into two sides by a hyperplane,
   * then recursively split each of those subtrees etc.
   * We create a tree like this q times. The default q is determined automatically
   * in such a way that we at most use 2x as much memory as the vectors take.
   */
  int _f;
  size_t _s;
  int _n_items;
  mt19937 _rng;
  normal_distribution<T> _nd;
  variate_generator<mt19937&,
		    normal_distribution<T> > _var_nor;
  void* _nodes; // Could either be mmapped, or point to a memory buffer that we reallocate
  int _n_nodes;
  int _nodes_size;
  vector<int> _roots;
  int _K;
  bool _loaded;
public:
  AnnoyIndex(int f) : _rng(), _nd(), _var_nor(_rng, _nd) {
    _f = f;
    _s = sizeof(node<T>) + sizeof(T) * f; // Size of each node
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _loaded = false;

    _K = (sizeof(T) * f + sizeof(int) * 2) / sizeof(int);
  }
  ~AnnoyIndex() {
    if (!_loaded && _nodes) {
      free(_nodes);
    }
  }

  void add_item(int item, const python::list& v) {
    _allocate_size(item+1);
    node<T>* n = _get(item);

    n->children[0] = 0;
    n->children[1] = 0;
    n->n_descendants = 1;

    for (int z = 0; z < _f; z++)
      n->v[z] = python::extract<T>(v[z]);

    if (item >= _n_items)
      _n_items = item + 1;
  }

  void build(int q) {
    _n_nodes = _n_items;
    while (1) {
      if (q == -1 && _n_nodes >= _n_items * 2)
	break;
      if (q != -1 && _roots.size() >= (size_t)q)
	break;
      printf("pass %zd...\n", _roots.size());

      vector<int> indices;
      for (int i = 0; i < _n_items; i++)
	indices.push_back(i);

      _roots.push_back(_make_tree(indices));
    }
    // Also, copy the roots into the last segment of the array
    // This way we can load them faster without reading the whole file
    _allocate_size(_n_nodes + _roots.size());
    for (size_t i = 0; i < _roots.size(); i++)
      memcpy(_get(_n_nodes + i), _get(_roots[i]), _s);
    _n_nodes += _roots.size();

    printf("has %d nodes\n", _n_nodes);
  }

  void save(const string& filename) {
    FILE *f = fopen(filename.c_str(), "w");

    fwrite(_nodes, _s, _n_nodes, f);

    fclose(f);

    free(_nodes);
    _n_items = 0;
    _n_nodes = 0;
    _nodes_size = 0;
    _nodes = NULL;
    _roots.clear();
    load(filename);
  }

  void load(const string& filename) {
    struct stat buf;
    stat(filename.c_str(), &buf);
    off_t size = buf.st_size;
    int fd = open(filename.c_str(), O_RDONLY, (mode_t)0400);
    _nodes = (node<T>*)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);

    _n_nodes = size / _s;

    // Find the roots by scanning the end of the file and taking the nodes with most descendants
    int m = -1;
    for (int i = _n_nodes - 1; i >= 0; i--) {
      int k = _get(i)->n_descendants;
      if (m == -1 || k == m) {
	_roots.push_back(i);
	m = k;
      } else {
	break;
      }
    }
    _loaded = true;
    _n_items = m;
    printf("found %lu roots with degree %d\n", _roots.size(), m);
  }

  inline T _cos(const T* x, const T* y) {
    T pp = 0, qq = 0, pq = 0;
    for (int z = 0; z < _f; z++) {
      pp += x[z] * x[z];
      qq += y[z] * y[z];
      pq += x[z] * y[z];
    }
    T ppqq = pp * qq;
    if (ppqq > 0) return pq / sqrt(ppqq);
    else return 0.0;
  }

  inline T get_cos(int i, int j) {
    const T* x = _get(i)->v;
    const T* y = _get(j)->v;
    return _cos(x, y);
  }

  python::list get_nns_by_item(int item, int n) {
    const node<T>* m = _get(item);
    return _get_all_nns(m->v, n);
  }
  python::list get_nns_by_vector(python::list v, int n) {
    vector<T> w(_f);
    for (int z = 0; z < _f; z++)
      w[z] = python::extract<T>(v[z]);
    return _get_all_nns(&w[0], n);
  }

  int get_n_items() {
    return _n_items;
  }
private:
  void _allocate_size(int n) {
    if (n > _nodes_size) {
      int new_nodes_size = (_nodes_size + 1) * 2;
      if (n > new_nodes_size)
	new_nodes_size = n;
      _nodes = realloc(_nodes, _s * new_nodes_size);
      memset((char *)_nodes + (_nodes_size * _s)/sizeof(char), 0, (new_nodes_size - _nodes_size) * _s);
      _nodes_size = new_nodes_size;
    }
  }

  inline node<T>* _get(int i) {
    return (node<T>*)((char *)_nodes + (_s * i)/sizeof(char));
  }

  int _make_tree(const vector<int >& indices) {
    if (indices.size() == 1)
      return indices[0];

    _allocate_size(_n_nodes + 1);
    int item = _n_nodes++;
    node<T>* m = _get(item);
    m->n_descendants = indices.size();

    if (indices.size() <= (size_t)_K) {
      for (size_t i = 0; i < indices.size(); i++)
	m->children[i] = indices[i];
      return item;
    }

    vector<int> children_indices[2];
    for (int attempt = 0; attempt < 20; attempt ++) {
      /*
       * Create a random hyperplane.
       * If all points end up on the same time, we try again.
       * We could in principle *construct* a plane so that we split
       * all items evenly, but I think that could violate the guarantees
       * given by just picking a hyperplane at random
       */
      for (int z = 0; z < _f; z++)
	m->v[z] = _var_nor();

      children_indices[0].clear();
      children_indices[1].clear();

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	node<T>* n = _get(j);
	if (!n) {
	  printf("node %d undef...\n", j);
	  continue;
	}
	T dot = 0;
	for (int z = 0; z < _f; z++) {
	  dot += m->v[z] * n->v[z];
	}
	while (dot == 0)
	  dot = _var_nor();
	children_indices[dot > 0].push_back(j);
      }

      if (children_indices[0].size() > 0 && children_indices[1].size() > 0) {
	break;
      }
    }

    while (children_indices[0].size() == 0 || children_indices[1].size() == 0) {
      // If we didn't find a hyperplane, just randomize sides as a last option
      if (indices.size() > 100000)
	printf("Failed splitting %lu items\n", indices.size());

      children_indices[0].clear();
      children_indices[1].clear();

      // Set the vector to 0.0
      for (int z = 0; z < _f; z++)
	m->v[z] = 0.0;

      for (size_t i = 0; i < indices.size(); i++) {
	int j = indices[i];
	// Just randomize...
	children_indices[_var_nor() > 0].push_back(j);
      }
    }

    int children_0 = _make_tree(children_indices[0]);
    int children_1 = _make_tree(children_indices[1]);

    // We need to fetch m again because it might have been reallocated
    m = _get(item);
    m->children[0] = children_0;
    m->children[1] = children_1;

    return item;
  }

  void _get_nns(const T* v, int i, vector<int>* result, int limit) {
    const node<T>* n = _get(i);

    if (n->n_descendants == 0) {
      // unknown item, nothing to do...
    } else if (n->n_descendants == 1) {
      result->push_back(i);
    } else if (n->n_descendants <= _K) {
      for (int j = 0; j < n->n_descendants; j++) {
	result->push_back(n->children[j]);
      }
    } else {
      T dot = 0;

      for (int z = 0; z < _f; z++)
	dot += v[z] * n->v[z];

      while (dot == 0) // Randomize side if the dot product is zero
	dot = _var_nor();

      _get_nns(v, n->children[dot > 0], result, limit);
      if (result->size() < (size_t)limit)
	_get_nns(v, n->children[dot < 0], result, limit);
    }
  }

  python::list _get_all_nns(const T* v, int n) {
    vector<pair<T, int> > nns_cos;

    for (size_t i = 0; i < _roots.size(); i++) {
      vector<int> nns;
      _get_nns(v, _roots[i], &nns, n);
      for (size_t j = 0; j < nns.size(); j++) {
	nns_cos.push_back(make_pair(_cos(v, _get(nns[j])->v), nns[j]));
      }
    }
    sort(nns_cos.begin(), nns_cos.end());
    int last = -1, length=0;
    python::list l;
    for (int i = (int)nns_cos.size() - 1; i >= 0 && length < n; i--) {
      if (nns_cos[i].second != last) {
	l.append(nns_cos[i].second);
	last = nns_cos[i].second;
	length++;
      }
    }
    return l;
  }
};

BOOST_PYTHON_MODULE(annoylib)
{
  python::class_<AnnoyIndex<float> >("AnnoyIndex", python::init<int>())
    .def("add_item",          &AnnoyIndex<float>::add_item)
    .def("build",             &AnnoyIndex<float>::build)
    .def("save",              &AnnoyIndex<float>::save)
    .def("load",              &AnnoyIndex<float>::load)
    .def("get_cos",           &AnnoyIndex<float>::get_cos)
    .def("get_nns_by_item",   &AnnoyIndex<float>::get_nns_by_item)
    .def("get_nns_by_vector", &AnnoyIndex<float>::get_nns_by_vector)
    .def("get_n_items",       &AnnoyIndex<float>::get_n_items);
}
<|endoftext|>


<commit_before>//************************************************************/
//
//	Ratio Style Implementation
//
//	Implements the SPXRatioStyle class, which describes the type of
//	ratio to be plotted in the ratio section. Ratio styles can
//	include: [data AND/OR reference AND/OR convolute] in the
//	numerator, and [data XOR reference XOR convolute] in the
//	demominator.
//
//	@Author: 	J. Gibson, C. Embree, T. Carli - CERN ATLAS
//	@Date:		25.09.2014
//	@Email:		gibsjose@mail.gvsu.edu
//
//************************************************************/
#include <iostream>
#include <sstream>

#include "SPXRatioStyle.h"
#include "SPXUtilities.h"
#include "SPXException.h"

//Class name for debug statements
const std::string cn = "SPXRatioStyle::";

//Must define the static debug variable in the implementation
bool SPXRatioStyle::debug;

//Constructs an SPXRatioStyle object with a given string (effectively
//	calls the Parse() method on the input string)
SPXRatioStyle::SPXRatioStyle(std::string &s, unsigned int pn, unsigned int rsn) {
	this->Clear();

	std::ostringstream pss;
	std::ostringstream rss;
	pss << "PLOT_" << pn;
	rss << "ratio_style_" << rsn;

	this->plotNumber = pss.str();
	this->ratioStyleNumber = rss.str();
	this->Parse(s);
}

//Takes a string argument in ONLY the following four forms:
//
//		data / convolute
//		convolute / data
//		convolute / reference
//		data / data
//
// Sets the numerator and denominator bitfields based on the input string
void SPXRatioStyle::Parse(std::string &s) {
	std::string mn = "Parse: ";

	if(debug) std::cout << cn << mn << "Parsing configuration string: " << s << std::endl;

	//Look for special ratio styles:
	//	data_stat	<-- Plot data/data statistical errors in ratio section
	//	data_tot	<-- Plot data/data total errors in ratio section

	if(!s.compare("data_stat")) {
		dataStat = true;
	}

	if(!s.compare("data_tot")) {
		dataTot = true;
	}

	std::string den;
	std::string num;

	//Clear the numerator/denominator each time it is parsed
	this->Clear();

	//Parse the string into numerator and denominator (delimit with '/')
	std::vector<std::string> v = SPXStringUtilities::ParseString(s, '/');

	if(v.size() != 2) {
		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Must be in one of the forms: data_stat OR data_tot OR numerator / denominator");
	}

	//Parse the numerator by commas
	num = v.at(0);

	//Obtain the denominator
	den = v.at(1);

	if(debug) std::cout << cn << mn << "Numerator set to: " << num << std::endl;
	if(debug) std::cout << cn << mn << "Denominator set to: " << den << std::endl;

	//Check the numerator and denominator for size errors
	if(num.empty()) {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Numerator must be EXACTLY one of: \"data\" or \"convolute\"");
	}
	if(den.empty()) {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Denominator must be EXACTLY one of: \"data\", \"reference\", or \"convolute\"");
	}

	//Validate the numerator
	if(!num.compare("data")) {
		if(debug) std::cout << cn << mn << "Found numerator string = \"data\"" << std::endl;
		numerator |= RS_DATA;
	}
	else if(!num.compare("reference")) {
		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Numerator cannot be \"reference\"");
		numerator = RS_INVALID;
	}
	else if(!num.compare("convolute")) {
		if(debug) std::cout << cn << mn << "Found numerator string = \"convolute\"" << std::endl;
		numerator |= RS_CONVOLUTE;
	}
	else {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		std::ostringstream oss;
		oss << "Incorrect ratio style: Unrecognized ratio numerator option: \"" << num << "\" is invalid";
		throw SPXINIParseException(plotNumber, ratioStyleNumber, oss.str());
	}

	//Validate the denominator
	if(!den.compare("data")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"data\"" << std::endl;
		denominator = RS_DATA;
	}
	else if(!den.compare("reference")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"reference\"" << std::endl;
		denominator = RS_REFERENCE;
	}
	else if(!den.compare("convolute")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"convolute\"" << std::endl;
		denominator = RS_CONVOLUTE;
	}
	else {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		std::ostringstream oss;
		oss << "Incorrect ratio style: Unrecognized ratio denominator option: \"" << den << "\" is invalid";
		throw SPXINIParseException(plotNumber, ratioStyleNumber, oss.str());
	}

	//Check for invalid combinations
	if(numerator == RS_DATA) {
		if(denominator == RS_REFERENCE) {
			numerator = RS_INVALID;
			denominator = RS_INVALID;
			throw SPXINIParseException(plotNumber, ratioStyleNumber, "Invalid ratio combination: data / reference is not supported");
		}
	}

	if(numerator == RS_CONVOLUTE) {
		if(denominator == RS_CONVOLUTE) {
			numerator = RS_INVALID;
			denominator = RS_INVALID;
			throw SPXINIParseException(plotNumber, ratioStyleNumber, "Invalid ratio combination: convolute / convolute is not supported");
		}
	}

	if(debug) std::cout << cn << mn << plotNumber << " " << ratioStyleNumber << ": Denominator = " << den << "(" << denominator << ")" << std::endl;
	if(debug) std::cout << cn << mn << plotNumber << " " << ratioStyleNumber << ": Numerator = " << num << "(" << numerator << ")" << std::endl;
}

//Print displays the output of ToString to the console
void SPXRatioStyle::Print(void) {
	std::string mn = "Print: ";
	std::cout << this->ToString() << std::endl;
}

//ToString does the opposite of Parse: it assembles a string based on
// the numerator and denominator bitfields
std::string SPXRatioStyle::ToString(void) {
	std::string mn = "ToString: ";

	//Empty style
	if(this->IsEmpty()) {
		return "";
	}

	//Check for validity
	if(!this->IsValid()) {
		return "INVALID_RATIO_STYLE";
	}

	//Build numerator and denominator
	std::string num;
	std::string den;

	if(numerator == RS_DATA) {
		num = "data";
	}
	else if(numerator == RS_CONVOLUTE) {
		num = "convolute";
	}

	if(denominator == RS_DATA) {
		den = "data";
	}
	else if(denominator == RS_REFERENCE) {
		den = "reference";
	}
	else if(denominator == RS_CONVOLUTE) {
		den = "convolute";
	}

	return num + " / " + den;
}

//Determines whether the ratio style is empty or not
bool SPXRatioStyle::IsEmpty(void) {
	std::string mn = "IsEmpty: ";

	if(!(numerator | denominator)) {
		return true;
	}

	return false;
}

//Determines the validity of the ratio style
bool SPXRatioStyle::IsValid(void) {
	std::string mn = "IsValid: ";

	//Empty numerator and denominator: valid, but empty
	if(this->IsEmpty()){
		if(debug) std::cout << cn << mn << "Empty numerator and denominator" << std::endl;
		return true;
	}

	//Only one of numerator OR denominator empty
	if((!!numerator) ^ (!!denominator)) {
		if(debug) std::cout << cn << mn << "Mismatch: numerator = " << numerator << " denominator = " << denominator << std::endl;
		return false;
	}

	if((numerator != RS_DATA) && (numerator != RS_CONVOLUTE)) {
		if(debug) std::cout << cn << mn << "Numerator is invalid: numerator = " << numerator << std::endl;
		return false;
	}

	if((denominator != RS_DATA) && (denominator != RS_REFERENCE) && (denominator != RS_CONVOLUTE)) {
		if(debug) std::cout << cn << mn << "Denominator is invalid: denominator = " << denominator << std::endl;
		return false;
	}

	return true;
}
<commit_msg>Fixing RatioStyle: data_stat and data_tot<commit_after>//************************************************************/
//
//	Ratio Style Implementation
//
//	Implements the SPXRatioStyle class, which describes the type of
//	ratio to be plotted in the ratio section. Ratio styles can
//	include: [data AND/OR reference AND/OR convolute] in the
//	numerator, and [data XOR reference XOR convolute] in the
//	demominator.
//
//	@Author: 	J. Gibson, C. Embree, T. Carli - CERN ATLAS
//	@Date:		25.09.2014
//	@Email:		gibsjose@mail.gvsu.edu
//
//************************************************************/
#include <iostream>
#include <sstream>

#include "SPXRatioStyle.h"
#include "SPXUtilities.h"
#include "SPXException.h"

//Class name for debug statements
const std::string cn = "SPXRatioStyle::";

//Must define the static debug variable in the implementation
bool SPXRatioStyle::debug;

//Constructs an SPXRatioStyle object with a given string (effectively
//	calls the Parse() method on the input string)
SPXRatioStyle::SPXRatioStyle(std::string &s, unsigned int pn, unsigned int rsn) {
	this->Clear();

	std::ostringstream pss;
	std::ostringstream rss;
	pss << "PLOT_" << pn;
	rss << "ratio_style_" << rsn;

	this->plotNumber = pss.str();
	this->ratioStyleNumber = rss.str();
	this->Parse(s);
}

//Takes a string argument in ONLY the following four forms:
//
//		data / convolute
//		convolute / data
//		convolute / reference
//		data / data
//
// Sets the numerator and denominator bitfields based on the input string
void SPXRatioStyle::Parse(std::string &s) {
	std::string mn = "Parse: ";

	if(debug) std::cout << cn << mn << "Parsing configuration string: " << s << std::endl;

	//Look for special ratio styles:
	//	data_stat	<-- Plot data/data statistical errors in ratio section
	//	data_tot	<-- Plot data/data total errors in ratio section

	if(!s.compare("data_stat")) {
		dataStat = true;
		if(debug) std::cout << cn << mn << "Ratio Style set to \"data_stat\"" << std::endl;
		return;
	}

	if(!s.compare("data_tot")) {
		dataTot = true;
		if(debug) std::cout << cn << mn << "Ratio Style set to \"data_tot\"" << std::endl;
		return;
	}

	std::string den;
	std::string num;

	//Clear the numerator/denominator each time it is parsed
	this->Clear();

	//Parse the string into numerator and denominator (delimit with '/')
	std::vector<std::string> v = SPXStringUtilities::ParseString(s, '/');

	if(v.size() != 2) {
		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Must be in one of the forms: data_stat OR data_tot OR numerator / denominator");
	}

	//Parse the numerator by commas
	num = v.at(0);

	//Obtain the denominator
	den = v.at(1);

	if(debug) std::cout << cn << mn << "Numerator set to: " << num << std::endl;
	if(debug) std::cout << cn << mn << "Denominator set to: " << den << std::endl;

	//Check the numerator and denominator for size errors
	if(num.empty()) {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Numerator must be EXACTLY one of: \"data\" or \"convolute\"");
	}
	if(den.empty()) {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Denominator must be EXACTLY one of: \"data\", \"reference\", or \"convolute\"");
	}

	//Validate the numerator
	if(!num.compare("data")) {
		if(debug) std::cout << cn << mn << "Found numerator string = \"data\"" << std::endl;
		numerator |= RS_DATA;
	}
	else if(!num.compare("reference")) {
		throw SPXINIParseException(plotNumber, ratioStyleNumber, "Incorrect ratio style: Numerator cannot be \"reference\"");
		numerator = RS_INVALID;
	}
	else if(!num.compare("convolute")) {
		if(debug) std::cout << cn << mn << "Found numerator string = \"convolute\"" << std::endl;
		numerator |= RS_CONVOLUTE;
	}
	else {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		std::ostringstream oss;
		oss << "Incorrect ratio style: Unrecognized ratio numerator option: \"" << num << "\" is invalid";
		throw SPXINIParseException(plotNumber, ratioStyleNumber, oss.str());
	}

	//Validate the denominator
	if(!den.compare("data")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"data\"" << std::endl;
		denominator = RS_DATA;
	}
	else if(!den.compare("reference")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"reference\"" << std::endl;
		denominator = RS_REFERENCE;
	}
	else if(!den.compare("convolute")) {
		if(debug) std::cout << cn << mn << "Found denominator string = \"convolute\"" << std::endl;
		denominator = RS_CONVOLUTE;
	}
	else {
		numerator = RS_INVALID;
		denominator = RS_INVALID;

		std::ostringstream oss;
		oss << "Incorrect ratio style: Unrecognized ratio denominator option: \"" << den << "\" is invalid";
		throw SPXINIParseException(plotNumber, ratioStyleNumber, oss.str());
	}

	//Check for invalid combinations
	if(numerator == RS_DATA) {
		if(denominator == RS_REFERENCE) {
			numerator = RS_INVALID;
			denominator = RS_INVALID;
			throw SPXINIParseException(plotNumber, ratioStyleNumber, "Invalid ratio combination: data / reference is not supported");
		}
	}

	if(numerator == RS_CONVOLUTE) {
		if(denominator == RS_CONVOLUTE) {
			numerator = RS_INVALID;
			denominator = RS_INVALID;
			throw SPXINIParseException(plotNumber, ratioStyleNumber, "Invalid ratio combination: convolute / convolute is not supported");
		}
	}

	if(debug) std::cout << cn << mn << plotNumber << " " << ratioStyleNumber << ": Denominator = " << den << "(" << denominator << ")" << std::endl;
	if(debug) std::cout << cn << mn << plotNumber << " " << ratioStyleNumber << ": Numerator = " << num << "(" << numerator << ")" << std::endl;
}

//Print displays the output of ToString to the console
void SPXRatioStyle::Print(void) {
	std::string mn = "Print: ";
	std::cout << this->ToString() << std::endl;
}

//ToString does the opposite of Parse: it assembles a string based on
// the numerator and denominator bitfields
std::string SPXRatioStyle::ToString(void) {
	std::string mn = "ToString: ";

	//Empty style
	if(this->IsEmpty()) {
		return "";
	}

	//Check for validity
	if(!this->IsValid()) {
		return "INVALID_RATIO_STYLE";
	}

	//Build numerator and denominator
	std::string num;
	std::string den;

	if(numerator == RS_DATA) {
		num = "data";
	}
	else if(numerator == RS_CONVOLUTE) {
		num = "convolute";
	}

	if(denominator == RS_DATA) {
		den = "data";
	}
	else if(denominator == RS_REFERENCE) {
		den = "reference";
	}
	else if(denominator == RS_CONVOLUTE) {
		den = "convolute";
	}

	return num + " / " + den;
}

//Determines whether the ratio style is empty or not
bool SPXRatioStyle::IsEmpty(void) {
	std::string mn = "IsEmpty: ";

	if(!(numerator | denominator)) {
		return true;
	}

	return false;
}

//Determines the validity of the ratio style
bool SPXRatioStyle::IsValid(void) {
	std::string mn = "IsValid: ";

	//Empty numerator and denominator: valid, but empty
	if(this->IsEmpty()){
		if(debug) std::cout << cn << mn << "Empty numerator and denominator" << std::endl;
		return true;
	}

	//Only one of numerator OR denominator empty
	if((!!numerator) ^ (!!denominator)) {
		if(debug) std::cout << cn << mn << "Mismatch: numerator = " << numerator << " denominator = " << denominator << std::endl;
		return false;
	}

	if((numerator != RS_DATA) && (numerator != RS_CONVOLUTE)) {
		if(debug) std::cout << cn << mn << "Numerator is invalid: numerator = " << numerator << std::endl;
		return false;
	}

	if((denominator != RS_DATA) && (denominator != RS_REFERENCE) && (denominator != RS_CONVOLUTE)) {
		if(debug) std::cout << cn << mn << "Denominator is invalid: denominator = " << denominator << std::endl;
		return false;
	}

	return true;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * xmlparser.cpp
 *****************************************************************************
 * Copyright (C) 2004 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "xmlparser.hpp"
#include "../src/os_factory.hpp"
#include <vlc_url.h>

#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif

XMLParser::XMLParser( intf_thread_t *pIntf, const string &rFileName,
                      bool useDTD ):
    SkinObject( pIntf )
{
    m_pReader = NULL;
    m_pStream = NULL;

    if( useDTD )
    {
        m_pXML = xml_Create( pIntf );
        if( m_pXML )
            LoadCatalog();
        else
        {
            msg_Err( getIntf(), "DTD not supported" );
            useDTD = false;
        }
    }
    else
        m_pXML = NULL;

    char* psz_uri = make_URI( rFileName.c_str(), NULL );
    m_pStream = stream_UrlNew( pIntf, psz_uri );
    free( psz_uri );

    if( !m_pStream )
    {
        msg_Err( getIntf(), "failed to open %s for reading",
                 rFileName.c_str() );
        return;
    }
    m_pReader = xml_ReaderCreate( m_pXML, m_pStream );
    if( !m_pReader )
    {
        msg_Err( getIntf(), "failed to open %s for parsing",
                 rFileName.c_str() );
        return;
    }

    xml_ReaderUseDTD( m_pReader, useDTD );
}

XMLParser::~XMLParser()
{
    if( m_pReader ) xml_ReaderDelete( m_pReader );
    if( m_pXML ) xml_Delete( m_pXML );
    if( m_pStream ) stream_Delete( m_pStream );
}

void XMLParser::LoadCatalog()
{
    // Get the resource path and look for the DTD
    OSFactory *pOSFactory = OSFactory::instance( getIntf() );
    const list<string> &resPath = pOSFactory->getResourcePath();
    const string &sep = pOSFactory->getDirSeparator();
    list<string>::const_iterator it;

#ifdef HAVE_SYS_STAT_H
    struct stat statBuf;

    // Try to load the catalog first (needed at least on win32 where
    // we don't have a default catalog)
    for( it = resPath.begin(); it != resPath.end(); it++ )
    {
        string catalog_path = (*it) + sep + "skin.catalog";
        if( !stat( catalog_path.c_str(), &statBuf ) )
        {
            msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() );
            xml_CatalogLoad( m_pXML, catalog_path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        // Ok, try the default one
        xml_CatalogLoad( m_pXML, 0 );
    }

    for( it = resPath.begin(); it != resPath.end(); it++ )
    {
        string path = (*it) + sep + "skin.dtd";
        if( !stat( path.c_str(), &statBuf ) )
        {
            // DTD found
            msg_Dbg( getIntf(), "using DTD %s", path.c_str() );

            // Add an entry in the default catalog
            xml_CatalogAdd( m_pXML, "public",
                            "-//VideoLAN//DTD VLC Skins V"
                            SKINS_DTD_VERSION "//EN", path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        msg_Err( getIntf(), "cannot find the skins DTD");
    }
#endif
}

bool XMLParser::parse()
{
    if( !m_pReader ) return false;

    m_errors = false;

    int ret = xml_ReaderRead( m_pReader );
    while( ret == 1 )
    {
        if( m_errors ) return false;

        // Get the node type
        int type = xml_ReaderNodeType( m_pReader );
        switch( type )
        {
            // Error
            case -1:
                return false;
                break;

            case XML_READER_STARTELEM:
            {
                // Read the element name
                char *eltName = xml_ReaderName( m_pReader );
                if( !eltName ) return false;

                // Read the attributes
                AttrList_t attributes;
                while( xml_ReaderNextAttr( m_pReader ) == VLC_SUCCESS )
                {
                    char *name = xml_ReaderName( m_pReader );
                    char *value = xml_ReaderValue( m_pReader );
                    if( !name || !value )
                    {
                        free( name );
                        free( value );
                        return false;
                    }
                    attributes[name] = value;
                }

                handleBeginElement( eltName, attributes );
                free( eltName );

                map<const char*, const char*, ltstr> ::iterator it =
                    attributes.begin();
                while( it != attributes.end() )
                {
                    free( (char *)it->first );
                    free( (char *)it->second );
                    it++;
                }
                break;
            }

            // End element
            case XML_READER_ENDELEM:
            {
                // Read the element name
                char *eltName = xml_ReaderName( m_pReader );
                if( !eltName ) return false;

                handleEndElement( eltName );
                free( eltName );
                break;
            }
        }
        ret = xml_ReaderRead( m_pReader );
    }
    return (ret == 0 && !m_errors );
}
<commit_msg>skins2: missing initialization<commit_after>/*****************************************************************************
 * xmlparser.cpp
 *****************************************************************************
 * Copyright (C) 2004 the VideoLAN team
 * $Id$
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "xmlparser.hpp"
#include "../src/os_factory.hpp"
#include <vlc_url.h>

#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif

XMLParser::XMLParser( intf_thread_t *pIntf, const string &rFileName,
                      bool useDTD ):
    SkinObject( pIntf )
{
    m_pReader = NULL;
    m_pStream = NULL;

    if( useDTD )
    {
        m_pXML = xml_Create( pIntf );
        if( m_pXML )
            LoadCatalog();
        else
        {
            msg_Err( getIntf(), "DTD not supported" );
            useDTD = false;
        }
    }
    else
        m_pXML = NULL;

    char* psz_uri = make_URI( rFileName.c_str(), NULL );
    m_pStream = stream_UrlNew( pIntf, psz_uri );
    free( psz_uri );

    if( !m_pStream )
    {
        msg_Err( getIntf(), "failed to open %s for reading",
                 rFileName.c_str() );
        m_pReader = NULL;
        return;
    }
    m_pReader = xml_ReaderCreate( m_pXML, m_pStream );
    if( !m_pReader )
    {
        msg_Err( getIntf(), "failed to open %s for parsing",
                 rFileName.c_str() );
        return;
    }

    xml_ReaderUseDTD( m_pReader, useDTD );
}

XMLParser::~XMLParser()
{
    if( m_pReader ) xml_ReaderDelete( m_pReader );
    if( m_pXML ) xml_Delete( m_pXML );
    if( m_pStream ) stream_Delete( m_pStream );
}

void XMLParser::LoadCatalog()
{
    // Get the resource path and look for the DTD
    OSFactory *pOSFactory = OSFactory::instance( getIntf() );
    const list<string> &resPath = pOSFactory->getResourcePath();
    const string &sep = pOSFactory->getDirSeparator();
    list<string>::const_iterator it;

#ifdef HAVE_SYS_STAT_H
    struct stat statBuf;

    // Try to load the catalog first (needed at least on win32 where
    // we don't have a default catalog)
    for( it = resPath.begin(); it != resPath.end(); it++ )
    {
        string catalog_path = (*it) + sep + "skin.catalog";
        if( !stat( catalog_path.c_str(), &statBuf ) )
        {
            msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() );
            xml_CatalogLoad( m_pXML, catalog_path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        // Ok, try the default one
        xml_CatalogLoad( m_pXML, 0 );
    }

    for( it = resPath.begin(); it != resPath.end(); it++ )
    {
        string path = (*it) + sep + "skin.dtd";
        if( !stat( path.c_str(), &statBuf ) )
        {
            // DTD found
            msg_Dbg( getIntf(), "using DTD %s", path.c_str() );

            // Add an entry in the default catalog
            xml_CatalogAdd( m_pXML, "public",
                            "-//VideoLAN//DTD VLC Skins V"
                            SKINS_DTD_VERSION "//EN", path.c_str() );
            break;
        }
    }
    if( it == resPath.end() )
    {
        msg_Err( getIntf(), "cannot find the skins DTD");
    }
#endif
}

bool XMLParser::parse()
{
    if( !m_pReader ) return false;

    m_errors = false;

    int ret = xml_ReaderRead( m_pReader );
    while( ret == 1 )
    {
        if( m_errors ) return false;

        // Get the node type
        int type = xml_ReaderNodeType( m_pReader );
        switch( type )
        {
            // Error
            case -1:
                return false;
                break;

            case XML_READER_STARTELEM:
            {
                // Read the element name
                char *eltName = xml_ReaderName( m_pReader );
                if( !eltName ) return false;

                // Read the attributes
                AttrList_t attributes;
                while( xml_ReaderNextAttr( m_pReader ) == VLC_SUCCESS )
                {
                    char *name = xml_ReaderName( m_pReader );
                    char *value = xml_ReaderValue( m_pReader );
                    if( !name || !value )
                    {
                        free( name );
                        free( value );
                        return false;
                    }
                    attributes[name] = value;
                }

                handleBeginElement( eltName, attributes );
                free( eltName );

                map<const char*, const char*, ltstr> ::iterator it =
                    attributes.begin();
                while( it != attributes.end() )
                {
                    free( (char *)it->first );
                    free( (char *)it->second );
                    it++;
                }
                break;
            }

            // End element
            case XML_READER_ENDELEM:
            {
                // Read the element name
                char *eltName = xml_ReaderName( m_pReader );
                if( !eltName ) return false;

                handleEndElement( eltName );
                free( eltName );
                break;
            }
        }
        ret = xml_ReaderRead( m_pReader );
    }
    return (ret == 0 && !m_errors );
}
<|endoftext|>


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

#include "appcast.h"
#include "error.h"

#include <expat.h>
#include <vector>
#include <algorithm>
#include <windows.h>

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                                XML parsing
 *--------------------------------------------------------------------------*/

namespace
{

#define MVAL(x) x
#define CONCAT3(a,b,c) MVAL(a)##MVAL(b)##MVAL(c)

#define NS_SPARKLE      "http://www.andymatuschak.org/xml-namespaces/sparkle"
#define NS_SEP          '#'
#define NS_SPARKLE_NAME(name) NS_SPARKLE "#" name

#define NODE_CHANNEL    "channel"
#define NODE_ITEM       "item"
#define NODE_RELNOTES   NS_SPARKLE_NAME("releaseNotesLink")
#define NODE_TITLE "title"
#define NODE_DESCRIPTION "description"
#define NODE_LINK       "link"
#define NODE_ENCLOSURE  "enclosure"
#define NODE_MIN_OS_VERSION NS_SPARKLE_NAME("minimumSystemVersion")
#define ATTR_URL        "url"
#define ATTR_VERSION    NS_SPARKLE_NAME("version")
#define ATTR_SHORTVERSION NS_SPARKLE_NAME("shortVersionString")
#define ATTR_OS         NS_SPARKLE_NAME("os")
#define ATTR_ARGUMENTS  NS_SPARKLE_NAME("installerArguments")
#define NODE_VERSION      ATTR_VERSION        // These can be nodes or
#define NODE_SHORTVERSION ATTR_SHORTVERSION   // attributes.
#define OS_MARKER       "windows"
#define OS_MARKER_LEN   7

// context data for the parser
struct ContextData
{
    ContextData(XML_Parser& p)
        : parser(p),
        in_channel(0), in_item(0), in_relnotes(0), in_title(0), in_description(0), in_link(0),
        in_version(0), in_shortversion(0), in_min_os_version(0)
    {}

    // the parser we're using
    XML_Parser& parser;

    // is inside <channel>, <item> or <sparkle:releaseNotesLink>, <title>, <description>, or <link> respectively?
    int in_channel, in_item, in_relnotes, in_title, in_description, in_link;

    // is inside <sparkle:version> or <sparkle:shortVersionString> node?
    int in_version, in_shortversion, in_min_os_version;

    // parsed <item>s
    std::vector<Appcast> items;
};

bool is_windows_version_acceptable(const Appcast &item)
{
    if (item.MinOSVersion.empty())
        return true;

    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, { 0 }, 0, 0 };
    DWORDLONG const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
        0, VER_MAJORVERSION, VER_GREATER_EQUAL),
        VER_MINORVERSION, VER_GREATER_EQUAL),
        VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    sscanf(item.MinOSVersion.c_str(), "%lu.%lu.%hu", &osvi.dwMajorVersion,
        &osvi.dwMinorVersion, &osvi.wServicePackMajor);

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION |
        VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}

void XMLCALL OnStartElement(void *data, const char *name, const char **attrs)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);

    if ( strcmp(name, NODE_CHANNEL) == 0 )
    {
        ctxt.in_channel++;
    }
    else if ( ctxt.in_channel && strcmp(name, NODE_ITEM) == 0 )
    {
        ctxt.in_item++;
        Appcast item;
        ctxt.items.push_back(item);
    }
    else if ( ctxt.in_item )
    {
        if ( strcmp(name, NODE_RELNOTES) == 0 )
        {
            ctxt.in_relnotes++;
        }
        else if ( strcmp(name, NODE_TITLE) == 0 )
        {
            ctxt.in_title++;
        }
        else if ( strcmp(name, NODE_DESCRIPTION) == 0 )
        {
            ctxt.in_description++;
        }
        else if ( strcmp(name, NODE_LINK) == 0 )
        {
            ctxt.in_link++;
        }
        else if ( strcmp(name, NODE_VERSION) == 0 )
        {
            ctxt.in_version++;
        }
        else if ( strcmp(name, NODE_SHORTVERSION) == 0 )
        {
            ctxt.in_shortversion++;
        }
        else if (strcmp(name, NODE_MIN_OS_VERSION) == 0)
        {
            ctxt.in_min_os_version++;
        }
        else if (strcmp(name, NODE_ENCLOSURE) == 0)
        {
            const size_t size = ctxt.items.size();
            for ( int i = 0; attrs[i]; i += 2 )
            {
                const char *name = attrs[i];
                const char *value = attrs[i+1];

                if ( strcmp(name, ATTR_URL) == 0 )
                    ctxt.items[size-1].DownloadURL = value;
                else if ( strcmp(name, ATTR_VERSION) == 0 )
                    ctxt.items[size-1].Version = value;
                else if ( strcmp(name, ATTR_SHORTVERSION) == 0 )
                    ctxt.items[size-1].ShortVersionString = value;
                else if ( strcmp(name, ATTR_OS) == 0 )
                    ctxt.items[size-1].Os = value;
                else if ( strcmp(name, ATTR_ARGUMENTS) == 0 )
                    ctxt.items[size-1].InstallerArguments = value;
            }
        }
    }
}

/**
 * Returns true if item os is exactly "windows"
 *   or if item is "windows-x64" on 64bit
 *   or if item is "windows-x86" on 32bit
 *   and is above minimum version
 */
bool is_suitable_windows_item(const Appcast &item)
{
    if (!is_windows_version_acceptable(item))
        return false;

    if (item.Os == OS_MARKER)
        return true;

    if (item.Os.compare(0, OS_MARKER_LEN, OS_MARKER) != 0)
        return false;

    // Check suffix for matching bitness
#ifdef _WIN64
    return item.Os.compare(OS_MARKER_LEN, std::string::npos, "-x64") == 0;
#else
    return item.Os.compare(OS_MARKER_LEN, std::string::npos, "-x86") == 0;
#endif
}

void XMLCALL OnEndElement(void *data, const char *name)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);

    if ( ctxt.in_item && strcmp(name, NODE_RELNOTES) == 0 )
    {
        ctxt.in_relnotes--;
    }
    else if ( ctxt.in_item && strcmp(name, NODE_TITLE) == 0 )
    {
        ctxt.in_title--;
    }
    else if ( ctxt.in_item && strcmp(name, NODE_DESCRIPTION) == 0 )
    {
        ctxt.in_description--;
    }
    else if ( ctxt.in_item && strcmp(name, NODE_MIN_OS_VERSION) == 0 )
    {
        ctxt.in_min_os_version--;
    }
    else if ( ctxt.in_link && strcmp(name, NODE_LINK) == 0 )
    {
        ctxt.in_link--;
    }
    else if ( ctxt.in_link && strcmp(name, NODE_VERSION) == 0 )
    {
        ctxt.in_version--;
    }
    else if ( ctxt.in_shortversion && strcmp(name, NODE_SHORTVERSION) == 0 )
    {
        ctxt.in_shortversion--;
    }
    else if (ctxt.in_channel && strcmp(name, NODE_ITEM) == 0)
    {
        ctxt.in_item--;
        if (is_suitable_windows_item(ctxt.items[ctxt.items.size() - 1]))
            XML_StopParser(ctxt.parser, XML_TRUE);
    }
    else if ( strcmp(name, NODE_CHANNEL) == 0 )
    {
        ctxt.in_channel--;
        // we've reached the end of <channel> element,
        // so we stop parsing
        XML_StopParser(ctxt.parser, XML_TRUE);
    }
}

void XMLCALL OnText(void *data, const char *s, int len)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);
    const size_t size = ctxt.items.size();

    if ( ctxt.in_relnotes )
        ctxt.items[size-1].ReleaseNotesURL.append(s, len);
    else if ( ctxt.in_title )
        ctxt.items[size-1].Title.append(s, len);
    else if ( ctxt.in_description )
        ctxt.items[size-1].Description.append(s, len);
    else if ( ctxt.in_link )
        ctxt.items[size-1].WebBrowserURL.append(s, len);
    else if ( ctxt.in_version )
        ctxt.items[size-1].Version.append(s, len);
    else if ( ctxt.in_shortversion )
        ctxt.items[size - 1].ShortVersionString.append(s, len);
    else if ( ctxt.in_min_os_version )
        ctxt.items[size - 1].MinOSVersion.append(s, len);
}

} // anonymous namespace

/*--------------------------------------------------------------------------*
                               Appcast class
 *--------------------------------------------------------------------------*/

Appcast Appcast::Load(const std::string& xml)
{
    XML_Parser p = XML_ParserCreateNS(NULL, NS_SEP);
    if ( !p )
        throw std::runtime_error("Failed to create XML parser.");

    ContextData ctxt(p);

    XML_SetUserData(p, &ctxt);
    XML_SetElementHandler(p, OnStartElement, OnEndElement);
    XML_SetCharacterDataHandler(p, OnText);

    XML_Status st = XML_Parse(p, xml.c_str(), (int)xml.size(), XML_TRUE);

    if ( st == XML_STATUS_ERROR )
    {
        std::string msg("XML parser error: ");
        msg.append(XML_ErrorString(XML_GetErrorCode(p)));
        XML_ParserFree(p);
        throw std::runtime_error(msg);
    }

    XML_ParserFree(p);

    if (ctxt.items.empty())
        return Appcast(); // invalid

    /*
     * Search for first <item> which specifies with the attribute sparkle:os set to "windows"
     * or "windows-x64"/"windows-x86" based on this modules bitness and meets the minimum
     * os version, if set. If none, use the first item that meets the minimum os version, if set.
     */
    std::vector<Appcast>::iterator it = std::find_if(ctxt.items.begin(), ctxt.items.end(), is_suitable_windows_item);
    if (it != ctxt.items.end())
        return *it;
    else
    {
        it = std::find_if(ctxt.items.begin(), ctxt.items.end(), is_windows_version_acceptable);
        if (it != ctxt.items.end())
            return *it;
        else
            return Appcast(); // There are no items that meet the set minimum os version
    }
}

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

#include "appcast.h"
#include "error.h"

#include <expat.h>
#include <vector>
#include <algorithm>
#include <windows.h>

namespace winsparkle
{

/*--------------------------------------------------------------------------*
                                XML parsing
 *--------------------------------------------------------------------------*/

namespace
{

#define MVAL(x) x
#define CONCAT3(a,b,c) MVAL(a)##MVAL(b)##MVAL(c)

#define NS_SPARKLE      "http://www.andymatuschak.org/xml-namespaces/sparkle"
#define NS_SEP          '#'
#define NS_SPARKLE_NAME(name) NS_SPARKLE "#" name

#define NODE_CHANNEL    "channel"
#define NODE_ITEM       "item"
#define NODE_RELNOTES   NS_SPARKLE_NAME("releaseNotesLink")
#define NODE_TITLE "title"
#define NODE_DESCRIPTION "description"
#define NODE_LINK       "link"
#define NODE_ENCLOSURE  "enclosure"
#define NODE_MIN_OS_VERSION NS_SPARKLE_NAME("minimumSystemVersion")
#define ATTR_URL        "url"
#define ATTR_VERSION    NS_SPARKLE_NAME("version")
#define ATTR_SHORTVERSION NS_SPARKLE_NAME("shortVersionString")
#define ATTR_OS         NS_SPARKLE_NAME("os")
#define ATTR_ARGUMENTS  NS_SPARKLE_NAME("installerArguments")
#define NODE_VERSION      ATTR_VERSION        // These can be nodes or
#define NODE_SHORTVERSION ATTR_SHORTVERSION   // attributes.
#define OS_MARKER       "windows"
#define OS_MARKER_LEN   7

// context data for the parser
struct ContextData
{
    ContextData(XML_Parser& p)
        : parser(p),
        in_channel(0), in_item(0), in_relnotes(0), in_title(0), in_description(0), in_link(0),
        in_version(0), in_shortversion(0), in_min_os_version(0)
    {}

    // the parser we're using
    XML_Parser& parser;

    // is inside <channel>, <item> or <sparkle:releaseNotesLink>, <title>, <description>, or <link> respectively?
    int in_channel, in_item, in_relnotes, in_title, in_description, in_link;

    // is inside <sparkle:version> or <sparkle:shortVersionString> node?
    int in_version, in_shortversion, in_min_os_version;

    // parsed <item>s
    std::vector<Appcast> items;
};

bool is_windows_version_acceptable(const Appcast &item)
{
    if (item.MinOSVersion.empty())
        return true;

    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, { 0 }, 0, 0 };
    DWORDLONG const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
        0, VER_MAJORVERSION, VER_GREATER_EQUAL),
        VER_MINORVERSION, VER_GREATER_EQUAL),
        VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    sscanf(item.MinOSVersion.c_str(), "%lu.%lu.%hu", &osvi.dwMajorVersion,
        &osvi.dwMinorVersion, &osvi.wServicePackMajor);

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION |
        VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}

void XMLCALL OnStartElement(void *data, const char *name, const char **attrs)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);

    if ( strcmp(name, NODE_CHANNEL) == 0 )
    {
        ctxt.in_channel++;
    }
    else if ( ctxt.in_channel && strcmp(name, NODE_ITEM) == 0 )
    {
        ctxt.in_item++;
        Appcast item;
        ctxt.items.push_back(item);
    }
    else if ( ctxt.in_item )
    {
        if ( strcmp(name, NODE_RELNOTES) == 0 )
        {
            ctxt.in_relnotes++;
        }
        else if ( strcmp(name, NODE_TITLE) == 0 )
        {
            ctxt.in_title++;
        }
        else if ( strcmp(name, NODE_DESCRIPTION) == 0 )
        {
            ctxt.in_description++;
        }
        else if ( strcmp(name, NODE_LINK) == 0 )
        {
            ctxt.in_link++;
        }
        else if ( strcmp(name, NODE_VERSION) == 0 )
        {
            ctxt.in_version++;
        }
        else if ( strcmp(name, NODE_SHORTVERSION) == 0 )
        {
            ctxt.in_shortversion++;
        }
        else if (strcmp(name, NODE_MIN_OS_VERSION) == 0)
        {
            ctxt.in_min_os_version++;
        }
        else if (strcmp(name, NODE_ENCLOSURE) == 0)
        {
            const size_t size = ctxt.items.size();
            for ( int i = 0; attrs[i]; i += 2 )
            {
                const char *name = attrs[i];
                const char *value = attrs[i+1];

                if ( strcmp(name, ATTR_URL) == 0 )
                    ctxt.items[size-1].DownloadURL = value;
                else if ( strcmp(name, ATTR_VERSION) == 0 )
                    ctxt.items[size-1].Version = value;
                else if ( strcmp(name, ATTR_SHORTVERSION) == 0 )
                    ctxt.items[size-1].ShortVersionString = value;
                else if ( strcmp(name, ATTR_OS) == 0 )
                    ctxt.items[size-1].Os = value;
                else if ( strcmp(name, ATTR_ARGUMENTS) == 0 )
                    ctxt.items[size-1].InstallerArguments = value;
            }
        }
    }
}

/**
 * Returns true if item os is exactly "windows"
 *   or if item is "windows-x64" on 64bit
 *   or if item is "windows-x86" on 32bit
 *   and is above minimum version
 */
bool is_suitable_windows_item(const Appcast &item)
{
    if (!is_windows_version_acceptable(item))
        return false;

    if (item.Os == OS_MARKER)
        return true;

    if (item.Os.compare(0, OS_MARKER_LEN, OS_MARKER) != 0)
        return false;

    // Check suffix for matching bitness
#ifdef _WIN64
    return item.Os.compare(OS_MARKER_LEN, std::string::npos, "-x64") == 0;
#else
    return item.Os.compare(OS_MARKER_LEN, std::string::npos, "-x86") == 0;
#endif
}

void XMLCALL OnEndElement(void *data, const char *name)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);

    if (ctxt.in_item)
    {
        if (strcmp(name, NODE_RELNOTES) == 0)
        {
            ctxt.in_relnotes--;
        }
        else if (strcmp(name, NODE_TITLE) == 0)
        {
            ctxt.in_title--;
        }
        else if (strcmp(name, NODE_DESCRIPTION) == 0)
        {
            ctxt.in_description--;
        }
        else if (strcmp(name, NODE_MIN_OS_VERSION) == 0)
        {
            ctxt.in_min_os_version--;
        }
        else if (strcmp(name, NODE_LINK) == 0)
        {
            ctxt.in_link--;
        }
        else if (strcmp(name, NODE_VERSION) == 0)
        {
            ctxt.in_version--;
        }
        else if (strcmp(name, NODE_SHORTVERSION) == 0)
        {
            ctxt.in_shortversion--;
        }
    }
    else if (ctxt.in_channel && strcmp(name, NODE_ITEM) == 0)
    {
        ctxt.in_item--;
        if (is_suitable_windows_item(ctxt.items[ctxt.items.size() - 1]))
            XML_StopParser(ctxt.parser, XML_TRUE);
    }
    else if (strcmp(name, NODE_CHANNEL) == 0 )
    {
        ctxt.in_channel--;
        // we've reached the end of <channel> element,
        // so we stop parsing
        XML_StopParser(ctxt.parser, XML_TRUE);
    }
}

void XMLCALL OnText(void *data, const char *s, int len)
{
    ContextData& ctxt = *static_cast<ContextData*>(data);
    const size_t size = ctxt.items.size();

    if ( ctxt.in_relnotes )
        ctxt.items[size-1].ReleaseNotesURL.append(s, len);
    else if ( ctxt.in_title )
        ctxt.items[size-1].Title.append(s, len);
    else if ( ctxt.in_description )
        ctxt.items[size-1].Description.append(s, len);
    else if ( ctxt.in_link )
        ctxt.items[size-1].WebBrowserURL.append(s, len);
    else if ( ctxt.in_version )
        ctxt.items[size-1].Version.append(s, len);
    else if ( ctxt.in_shortversion )
        ctxt.items[size - 1].ShortVersionString.append(s, len);
    else if ( ctxt.in_min_os_version )
        ctxt.items[size - 1].MinOSVersion.append(s, len);
}

} // anonymous namespace

/*--------------------------------------------------------------------------*
                               Appcast class
 *--------------------------------------------------------------------------*/

Appcast Appcast::Load(const std::string& xml)
{
    XML_Parser p = XML_ParserCreateNS(NULL, NS_SEP);
    if ( !p )
        throw std::runtime_error("Failed to create XML parser.");

    ContextData ctxt(p);

    XML_SetUserData(p, &ctxt);
    XML_SetElementHandler(p, OnStartElement, OnEndElement);
    XML_SetCharacterDataHandler(p, OnText);

    XML_Status st = XML_Parse(p, xml.c_str(), (int)xml.size(), XML_TRUE);

    if ( st == XML_STATUS_ERROR )
    {
        std::string msg("XML parser error: ");
        msg.append(XML_ErrorString(XML_GetErrorCode(p)));
        XML_ParserFree(p);
        throw std::runtime_error(msg);
    }

    XML_ParserFree(p);

    if (ctxt.items.empty())
        return Appcast(); // invalid

    /*
     * Search for first <item> which specifies with the attribute sparkle:os set to "windows"
     * or "windows-x64"/"windows-x86" based on this modules bitness and meets the minimum
     * os version, if set. If none, use the first item that meets the minimum os version, if set.
     */
    std::vector<Appcast>::iterator it = std::find_if(ctxt.items.begin(), ctxt.items.end(), is_suitable_windows_item);
    if (it != ctxt.items.end())
        return *it;
    else
    {
        it = std::find_if(ctxt.items.begin(), ctxt.items.end(), is_windows_version_acceptable);
        if (it != ctxt.items.end())
            return *it;
        else
            return Appcast(); // There are no items that meet the set minimum os version
    }
}

} // namespace winsparkle
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright 2012-2016 Masanori Morise. All Rights Reserved.
// Author: mmorise [at] yamanashi.ac.jp (Masanori Morise)
//
// common.cpp includes functions used in at least two files.
// (1) Common functions
// (2) FFT, IFFT and minimum phase analysis.
//
// In FFT analysis and minimum phase analysis,
// Functions "Initialize*()" allocate the mamory.
// Functions "Destroy*()" free the accolated memory.
// FFT size is used for initialization, and structs are used to keep the memory.
// Functions "GetMinimumPhaseSpectrum()" calculate minimum phase spectrum.
// Forward and inverse FFT do not have the function "Get*()",
// because forward FFT and inverse FFT can run in one step.
//
//-----------------------------------------------------------------------------
#include "./common.h"

#include <math.h>

#include "./constantnumbers.h"
#include "./matlabfunctions.h"

namespace {
//-----------------------------------------------------------------------------
// SetParametersForLinearSmoothing() is used in LinearSmoothing()
//-----------------------------------------------------------------------------
void SetParametersForLinearSmoothing(int boundary, int fft_size, int fs,
    double width, const double *power_spectrum, double *mirroring_spectrum,
    double *mirroring_segment, double *frequency_axis) {
  for (int i = 0; i < boundary; ++i)
    mirroring_spectrum[i] = power_spectrum[boundary - i];
  for (int i = boundary; i < fft_size / 2 + boundary; ++i)
    mirroring_spectrum[i] = power_spectrum[i - boundary];
  for (int i = fft_size / 2 + boundary; i <= fft_size / 2 + boundary * 2; ++i)
    mirroring_spectrum[i] =
      power_spectrum[fft_size / 2 - (i - (fft_size / 2 + boundary))];

  mirroring_segment[0] = mirroring_spectrum[0] * fs / fft_size;
  for (int i = 1; i < fft_size / 2 + boundary * 2 + 1; ++i)
    mirroring_segment[i] = mirroring_spectrum[i] * fs / fft_size +
    mirroring_segment[i - 1];

  for (int i = 0; i <= fft_size / 2; ++i)
    frequency_axis[i] = static_cast<double>(i) / fft_size *
    fs - width / 2.0;
}
}

//-----------------------------------------------------------------------------
// Fundamental functions
int GetSuitableFFTSize(int sample) {
  return static_cast<int>(pow(2.0,
    static_cast<int>(log(static_cast<double>(sample)) / world::kLog2) + 1.0));
}

//-----------------------------------------------------------------------------
// DCCorrection() corrects the input spectrum from 0 to f0 Hz because the
// general signal does not contain the DC (Direct Current) component.
// It is used in CheapTrick() and D4C().
//-----------------------------------------------------------------------------
void DCCorrection(const double *input, double current_f0, int fs, int fft_size,
    double *output) {
  int upper_limit = 1 +
    static_cast<int>(1.2 * current_f0 * fft_size / fs);
  double *low_frequency_replica = new double[upper_limit];
  double *low_frequency_axis = new double[upper_limit];

  for (int i = 0; i < upper_limit; ++i)
    low_frequency_axis[i] = static_cast<double>(i) * fs / fft_size;

  int upper_limit_replica = 1 + static_cast<int>(current_f0 * fft_size / fs);
  interp1Q(current_f0 - low_frequency_axis[0],
      -static_cast<double>(fs) / fft_size, input, upper_limit + 1,
      low_frequency_axis, upper_limit_replica, low_frequency_replica);

  for (int i = 0; i < upper_limit_replica; ++i)
    output[i] = input[i] + low_frequency_replica[i];

  delete[] low_frequency_replica;
  delete[] low_frequency_axis;
}

//-----------------------------------------------------------------------------
// LinearSmoothing() carries out the spectral smoothing by rectangular window
// whose length is width Hz and is used in CheapTrick() and D4C().
//-----------------------------------------------------------------------------
void LinearSmoothing(const double *input, double width, int fs, int fft_size,
    double *output) {
  int boundary = static_cast<int>(width * fft_size / fs) + 1;

  // These parameters are set by the other function.
  double *mirroring_spectrum = new double[fft_size / 2 + boundary * 2 + 1];
  double *mirroring_segment = new double[fft_size / 2 + boundary * 2 + 1];
  double *frequency_axis = new double[fft_size / 2 + 1];
  SetParametersForLinearSmoothing(boundary, fft_size, fs, width,
      input, mirroring_spectrum, mirroring_segment, frequency_axis);

  double *low_levels = new double[fft_size / 2 + 1];
  double *high_levels = new double[fft_size / 2 + 1];
  double origin_of_mirroring_axis =
    -(static_cast<double>(boundary) - 0.5) * fs / fft_size;
  double discrete_frequency_interval = static_cast<double>(fs) / fft_size;

  interp1Q(origin_of_mirroring_axis, discrete_frequency_interval,
      mirroring_segment, fft_size / 2 + boundary * 2 + 1, frequency_axis,
      fft_size / 2 + 1, low_levels);

  for (int i = 0; i <= fft_size / 2; ++i) frequency_axis[i] += width;

  interp1Q(origin_of_mirroring_axis, discrete_frequency_interval,
      mirroring_segment, fft_size / 2 + boundary * 2 + 1, frequency_axis,
      fft_size / 2 + 1, high_levels);

  for (int i = 0; i <= fft_size / 2; ++i)
    output[i] = (high_levels[i] - low_levels[i]) / width;

  delete[] mirroring_spectrum;
  delete[] mirroring_segment;
  delete[] frequency_axis;
  delete[] low_levels;
  delete[] high_levels;
}

//-----------------------------------------------------------------------------
// NuttallWindow() calculates the coefficients of Nuttall window whose length
// is y_length and is used in Dio() and D4C().
//-----------------------------------------------------------------------------
void NuttallWindow(int y_length, double *y) {
  double tmp;
  for (int i = 0; i < y_length; ++i) {
    tmp  = static_cast<double>(i) / (y_length - 1);
    y[i] = 0.355768 - 0.487396 * cos(2.0 * world::kPi * tmp) +
      0.144232 * cos(4.0 * world::kPi * tmp) -
      0.012604 * cos(6.0 * world::kPi * tmp);
  }
}

//-----------------------------------------------------------------------------
// FFT, IFFT and minimum phase analysis
void InitializeForwardRealFFT(int fft_size, ForwardRealFFT *forward_real_fft) {
  forward_real_fft->fft_size = fft_size;
  forward_real_fft->waveform = new double[fft_size];
  forward_real_fft->spectrum = new fft_complex[fft_size];
  forward_real_fft->forward_fft = fft_plan_dft_r2c_1d(fft_size,
      forward_real_fft->waveform, forward_real_fft->spectrum, FFT_ESTIMATE);
}

void DestroyForwardRealFFT(const ForwardRealFFT *forward_real_fft) {
  fft_destroy_plan(forward_real_fft->forward_fft);
  delete[] forward_real_fft->spectrum;
  delete[] forward_real_fft->waveform;
}

void InitializeInverseRealFFT(int fft_size, InverseRealFFT *inverse_real_fft) {
  inverse_real_fft->fft_size = fft_size;
  inverse_real_fft->waveform = new double[fft_size];
  inverse_real_fft->spectrum = new fft_complex[fft_size];
  inverse_real_fft->inverse_fft = fft_plan_dft_c2r_1d(fft_size,
      inverse_real_fft->spectrum, inverse_real_fft->waveform, FFT_ESTIMATE);
}

void DestroyInverseRealFFT(const InverseRealFFT *inverse_real_fft) {
  fft_destroy_plan(inverse_real_fft->inverse_fft);
  delete[] inverse_real_fft->spectrum;
  delete[] inverse_real_fft->waveform;
}

void InitializeMinimumPhaseAnalysis(int fft_size,
    MinimumPhaseAnalysis *minimum_phase) {
  minimum_phase->fft_size = fft_size;
  minimum_phase->log_spectrum = new double[fft_size];
  minimum_phase->minimum_phase_spectrum = new fft_complex[fft_size];
  minimum_phase->cepstrum = new fft_complex[fft_size];
  minimum_phase->inverse_fft = fft_plan_dft_r2c_1d(fft_size,
      minimum_phase->log_spectrum, minimum_phase->cepstrum, FFT_ESTIMATE);
  minimum_phase->forward_fft = fft_plan_dft_1d(fft_size,
      minimum_phase->cepstrum, minimum_phase->minimum_phase_spectrum,
      FFT_FORWARD, FFT_ESTIMATE);
}

void GetMinimumPhaseSpectrum(const MinimumPhaseAnalysis *minimum_phase) {
  // Mirroring
  for (int i = minimum_phase->fft_size / 2 + 1;
      i < minimum_phase->fft_size; ++i)
    minimum_phase->log_spectrum[i] =
    minimum_phase->log_spectrum[minimum_phase->fft_size - i];

  // This fft_plan carries out "forward" FFT.
  // To carriy out the Inverse FFT, the sign of imaginary part
  // is inverted after FFT.
  fft_execute(minimum_phase->inverse_fft);
  minimum_phase->cepstrum[0][1] *= -1.0;
  for (int i = 1; i < minimum_phase->fft_size / 2; ++i) {
    minimum_phase->cepstrum[i][0] *= 2.0;
    minimum_phase->cepstrum[i][1] *= -2.0;
  }
  minimum_phase->cepstrum[minimum_phase->fft_size / 2][1] *= -1.0;
  for (int i = minimum_phase->fft_size / 2 + 1;
      i < minimum_phase->fft_size; ++i) {
    minimum_phase->cepstrum[i][0] = 0.0;
    minimum_phase->cepstrum[i][1] = 0.0;
  }

  fft_execute(minimum_phase->forward_fft);

  // Since x is complex number, calculation of exp(x) is as following.
  // Note: This FFT library does not keep the aliasing.
  double tmp;
  for (int i = 0; i <= minimum_phase->fft_size / 2; ++i) {
    tmp = exp(minimum_phase->minimum_phase_spectrum[i][0] /
      minimum_phase->fft_size);
    minimum_phase->minimum_phase_spectrum[i][0] = tmp *
      cos(minimum_phase->minimum_phase_spectrum[i][1] /
      minimum_phase->fft_size);
    minimum_phase->minimum_phase_spectrum[i][1] = tmp *
      sin(minimum_phase->minimum_phase_spectrum[i][1] /
      minimum_phase->fft_size);
  }
}

void DestroyMinimumPhaseAnalysis(const MinimumPhaseAnalysis *minimum_phase) {
  fft_destroy_plan(minimum_phase->forward_fft);
  fft_destroy_plan(minimum_phase->inverse_fft);
  delete[] minimum_phase->cepstrum;
  delete[] minimum_phase->log_spectrum;
  delete[] minimum_phase->minimum_phase_spectrum;
}
<commit_msg>Do not use const for methods that destroy objects in common.cpp.<commit_after>//-----------------------------------------------------------------------------
// Copyright 2012-2016 Masanori Morise. All Rights Reserved.
// Author: mmorise [at] yamanashi.ac.jp (Masanori Morise)
//
// common.cpp includes functions used in at least two files.
// (1) Common functions
// (2) FFT, IFFT and minimum phase analysis.
//
// In FFT analysis and minimum phase analysis,
// Functions "Initialize*()" allocate the mamory.
// Functions "Destroy*()" free the accolated memory.
// FFT size is used for initialization, and structs are used to keep the memory.
// Functions "GetMinimumPhaseSpectrum()" calculate minimum phase spectrum.
// Forward and inverse FFT do not have the function "Get*()",
// because forward FFT and inverse FFT can run in one step.
//
//-----------------------------------------------------------------------------
#include "./common.h"

#include <math.h>

#include "./constantnumbers.h"
#include "./matlabfunctions.h"

namespace {
//-----------------------------------------------------------------------------
// SetParametersForLinearSmoothing() is used in LinearSmoothing()
//-----------------------------------------------------------------------------
void SetParametersForLinearSmoothing(int boundary, int fft_size, int fs,
    double width, const double *power_spectrum, double *mirroring_spectrum,
    double *mirroring_segment, double *frequency_axis) {
  for (int i = 0; i < boundary; ++i)
    mirroring_spectrum[i] = power_spectrum[boundary - i];
  for (int i = boundary; i < fft_size / 2 + boundary; ++i)
    mirroring_spectrum[i] = power_spectrum[i - boundary];
  for (int i = fft_size / 2 + boundary; i <= fft_size / 2 + boundary * 2; ++i)
    mirroring_spectrum[i] =
      power_spectrum[fft_size / 2 - (i - (fft_size / 2 + boundary))];

  mirroring_segment[0] = mirroring_spectrum[0] * fs / fft_size;
  for (int i = 1; i < fft_size / 2 + boundary * 2 + 1; ++i)
    mirroring_segment[i] = mirroring_spectrum[i] * fs / fft_size +
    mirroring_segment[i - 1];

  for (int i = 0; i <= fft_size / 2; ++i)
    frequency_axis[i] = static_cast<double>(i) / fft_size *
    fs - width / 2.0;
}
}

//-----------------------------------------------------------------------------
// Fundamental functions
int GetSuitableFFTSize(int sample) {
  return static_cast<int>(pow(2.0,
    static_cast<int>(log(static_cast<double>(sample)) / world::kLog2) + 1.0));
}

//-----------------------------------------------------------------------------
// DCCorrection() corrects the input spectrum from 0 to f0 Hz because the
// general signal does not contain the DC (Direct Current) component.
// It is used in CheapTrick() and D4C().
//-----------------------------------------------------------------------------
void DCCorrection(const double *input, double current_f0, int fs, int fft_size,
    double *output) {
  int upper_limit = 1 +
    static_cast<int>(1.2 * current_f0 * fft_size / fs);
  double *low_frequency_replica = new double[upper_limit];
  double *low_frequency_axis = new double[upper_limit];

  for (int i = 0; i < upper_limit; ++i)
    low_frequency_axis[i] = static_cast<double>(i) * fs / fft_size;

  int upper_limit_replica = 1 + static_cast<int>(current_f0 * fft_size / fs);
  interp1Q(current_f0 - low_frequency_axis[0],
      -static_cast<double>(fs) / fft_size, input, upper_limit + 1,
      low_frequency_axis, upper_limit_replica, low_frequency_replica);

  for (int i = 0; i < upper_limit_replica; ++i)
    output[i] = input[i] + low_frequency_replica[i];

  delete[] low_frequency_replica;
  delete[] low_frequency_axis;
}

//-----------------------------------------------------------------------------
// LinearSmoothing() carries out the spectral smoothing by rectangular window
// whose length is width Hz and is used in CheapTrick() and D4C().
//-----------------------------------------------------------------------------
void LinearSmoothing(const double *input, double width, int fs, int fft_size,
    double *output) {
  int boundary = static_cast<int>(width * fft_size / fs) + 1;

  // These parameters are set by the other function.
  double *mirroring_spectrum = new double[fft_size / 2 + boundary * 2 + 1];
  double *mirroring_segment = new double[fft_size / 2 + boundary * 2 + 1];
  double *frequency_axis = new double[fft_size / 2 + 1];
  SetParametersForLinearSmoothing(boundary, fft_size, fs, width,
      input, mirroring_spectrum, mirroring_segment, frequency_axis);

  double *low_levels = new double[fft_size / 2 + 1];
  double *high_levels = new double[fft_size / 2 + 1];
  double origin_of_mirroring_axis =
    -(static_cast<double>(boundary) - 0.5) * fs / fft_size;
  double discrete_frequency_interval = static_cast<double>(fs) / fft_size;

  interp1Q(origin_of_mirroring_axis, discrete_frequency_interval,
      mirroring_segment, fft_size / 2 + boundary * 2 + 1, frequency_axis,
      fft_size / 2 + 1, low_levels);

  for (int i = 0; i <= fft_size / 2; ++i) frequency_axis[i] += width;

  interp1Q(origin_of_mirroring_axis, discrete_frequency_interval,
      mirroring_segment, fft_size / 2 + boundary * 2 + 1, frequency_axis,
      fft_size / 2 + 1, high_levels);

  for (int i = 0; i <= fft_size / 2; ++i)
    output[i] = (high_levels[i] - low_levels[i]) / width;

  delete[] mirroring_spectrum;
  delete[] mirroring_segment;
  delete[] frequency_axis;
  delete[] low_levels;
  delete[] high_levels;
}

//-----------------------------------------------------------------------------
// NuttallWindow() calculates the coefficients of Nuttall window whose length
// is y_length and is used in Dio() and D4C().
//-----------------------------------------------------------------------------
void NuttallWindow(int y_length, double *y) {
  double tmp;
  for (int i = 0; i < y_length; ++i) {
    tmp  = static_cast<double>(i) / (y_length - 1);
    y[i] = 0.355768 - 0.487396 * cos(2.0 * world::kPi * tmp) +
      0.144232 * cos(4.0 * world::kPi * tmp) -
      0.012604 * cos(6.0 * world::kPi * tmp);
  }
}

//-----------------------------------------------------------------------------
// FFT, IFFT and minimum phase analysis
void InitializeForwardRealFFT(int fft_size, ForwardRealFFT *forward_real_fft) {
  forward_real_fft->fft_size = fft_size;
  forward_real_fft->waveform = new double[fft_size];
  forward_real_fft->spectrum = new fft_complex[fft_size];
  forward_real_fft->forward_fft = fft_plan_dft_r2c_1d(fft_size,
      forward_real_fft->waveform, forward_real_fft->spectrum, FFT_ESTIMATE);
}

void DestroyForwardRealFFT(ForwardRealFFT *forward_real_fft) {
  fft_destroy_plan(forward_real_fft->forward_fft);
  delete[] forward_real_fft->spectrum;
  delete[] forward_real_fft->waveform;
}

void InitializeInverseRealFFT(int fft_size, InverseRealFFT *inverse_real_fft) {
  inverse_real_fft->fft_size = fft_size;
  inverse_real_fft->waveform = new double[fft_size];
  inverse_real_fft->spectrum = new fft_complex[fft_size];
  inverse_real_fft->inverse_fft = fft_plan_dft_c2r_1d(fft_size,
      inverse_real_fft->spectrum, inverse_real_fft->waveform, FFT_ESTIMATE);
}

void DestroyInverseRealFFT(InverseRealFFT *inverse_real_fft) {
  fft_destroy_plan(inverse_real_fft->inverse_fft);
  delete[] inverse_real_fft->spectrum;
  delete[] inverse_real_fft->waveform;
}

void InitializeMinimumPhaseAnalysis(int fft_size,
    MinimumPhaseAnalysis *minimum_phase) {
  minimum_phase->fft_size = fft_size;
  minimum_phase->log_spectrum = new double[fft_size];
  minimum_phase->minimum_phase_spectrum = new fft_complex[fft_size];
  minimum_phase->cepstrum = new fft_complex[fft_size];
  minimum_phase->inverse_fft = fft_plan_dft_r2c_1d(fft_size,
      minimum_phase->log_spectrum, minimum_phase->cepstrum, FFT_ESTIMATE);
  minimum_phase->forward_fft = fft_plan_dft_1d(fft_size,
      minimum_phase->cepstrum, minimum_phase->minimum_phase_spectrum,
      FFT_FORWARD, FFT_ESTIMATE);
}

void GetMinimumPhaseSpectrum(const MinimumPhaseAnalysis *minimum_phase) {
  // Mirroring
  for (int i = minimum_phase->fft_size / 2 + 1;
      i < minimum_phase->fft_size; ++i)
    minimum_phase->log_spectrum[i] =
    minimum_phase->log_spectrum[minimum_phase->fft_size - i];

  // This fft_plan carries out "forward" FFT.
  // To carriy out the Inverse FFT, the sign of imaginary part
  // is inverted after FFT.
  fft_execute(minimum_phase->inverse_fft);
  minimum_phase->cepstrum[0][1] *= -1.0;
  for (int i = 1; i < minimum_phase->fft_size / 2; ++i) {
    minimum_phase->cepstrum[i][0] *= 2.0;
    minimum_phase->cepstrum[i][1] *= -2.0;
  }
  minimum_phase->cepstrum[minimum_phase->fft_size / 2][1] *= -1.0;
  for (int i = minimum_phase->fft_size / 2 + 1;
      i < minimum_phase->fft_size; ++i) {
    minimum_phase->cepstrum[i][0] = 0.0;
    minimum_phase->cepstrum[i][1] = 0.0;
  }

  fft_execute(minimum_phase->forward_fft);

  // Since x is complex number, calculation of exp(x) is as following.
  // Note: This FFT library does not keep the aliasing.
  double tmp;
  for (int i = 0; i <= minimum_phase->fft_size / 2; ++i) {
    tmp = exp(minimum_phase->minimum_phase_spectrum[i][0] /
      minimum_phase->fft_size);
    minimum_phase->minimum_phase_spectrum[i][0] = tmp *
      cos(minimum_phase->minimum_phase_spectrum[i][1] /
      minimum_phase->fft_size);
    minimum_phase->minimum_phase_spectrum[i][1] = tmp *
      sin(minimum_phase->minimum_phase_spectrum[i][1] /
      minimum_phase->fft_size);
  }
}

void DestroyMinimumPhaseAnalysis(MinimumPhaseAnalysis *minimum_phase) {
  fft_destroy_plan(minimum_phase->forward_fft);
  fft_destroy_plan(minimum_phase->inverse_fft);
  delete[] minimum_phase->cepstrum;
  delete[] minimum_phase->log_spectrum;
  delete[] minimum_phase->minimum_phase_spectrum;
}
<|endoftext|>