<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __STORE_H
#define __STORE_H

#include "core-forward-decl.hh"
#include "memword.hh"
#include "storage.hh"
#include "type.hh"

/**
 * A value node in the store.
 * The store is entirely made of nodes. A node is basically a typed value.
 * Non-atomic values, such as records, contain references to other nodes in the
 * store, hence forming a graph, and the name "node".
 * There are two kinds of node: stable and unstable node. A stable node is
 * guaranteed never to change, whereas unstable node can change. In order to
 * maintain consistency in the store, non-atomic values are only allowed to
 * reference stable nodes. Unstable nodes are used for working data, and
 * inherently mutable data (such as the contents of a cell).
 */
class Node {
public:
  template<class T, class... Args>
  void make(VM vm, Args... args) {
    typedef Accessor<T, typename Storage<T>::Type> Access;
    Access::init(type, value, vm, args...);
  }

  inline void reset(VM vm);

  union {
    // Regular structure of a node
    struct {
      const Type* type;
      MemWord value;
    };

    // Garbage collector hack
    struct {
      Node* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Stable node, which is guaranteed never to change
 */
class StableNode {
public:
  inline void init(VM vm, UnstableNode& from);
private:
  friend class UnstableNode;
public: // TODO make it private once the development has been bootstrapped
  Node node;
};

/**
 * Unstable node, which is allowed to change over time
 */
class UnstableNode {
public:
  UnstableNode() {}

  UnstableNode(VM vm, StableNode& from) {
    copy(vm, from);
  }

  UnstableNode(VM vm, UnstableNode& from) {
    copy(vm, from);
  }

  inline void copy(VM vm, StableNode& from);
  inline void copy(VM vm, UnstableNode& from);
  inline void swap(UnstableNode& from);
  inline void reset(VM vm);

  template<class T, class... Args>
  void make(VM vm, Args... args) {
    node.make<T>(vm, args...);
  }
private:
  friend class StableNode;
public: // TODO make it private once the development has been bootstrapped
  Node node;
};

/**
 * Base class for Self types
 */
template <class T>
class BaseSelf {
protected:
  typedef typename Storage<T>::Type StorageType;
  typedef Accessor<T, StorageType> Access;
public:
  BaseSelf(Node* node) : _node(node) {}

  template<class U, class... Args>
  void make(VM vm, Args... args) {
    _node->make<U>(vm, args...);
  }

  operator Node*() {
    return _node;
  }

  Node& operator*() {
    return *_node;
  }
protected:
  auto getBase() -> decltype(Access::get(MemWord())) {
    return Access::get(_node->value);
  }

  Node* _node;
};

/**
 * Self type for custom storage-based types
 */
template <class T>
class CustomStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  CustomStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl get() {
    return this->getBase();
  }
};

/**
 * Self type for default storage-based types
 */
template <class T>
class DefaultStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  DefaultStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return &this->getBase();
  }
};

/**
 * Extractor function for the template parameters of ImplWithArray
 * Given
 *   typedef ImplWithArray<I, E> T;
 * this provides
 *   ExtractImplWithArray<T>::Impl === I
 *   ExtractImplWithArray<T>::Elem === E
 */
template <class S>
struct ExtractImplWithArray {};

template <class I, class E>
struct ExtractImplWithArray<ImplWithArray<I, E>> {
  typedef I Impl;
  typedef E Elem;
};

/**
 * Self type for ImplWithArray-based types
 */
template <class T>
class ImplWithArraySelf: public BaseSelf<T> {
private:
  typedef typename BaseSelf<T>::StorageType StorageType;
  typedef typename ExtractImplWithArray<StorageType>::Impl Impl;
  typedef typename ExtractImplWithArray<StorageType>::Elem Elem;
public:
  ImplWithArraySelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return get().operator->();
  }

  Elem& operator[](size_t i) {
    return get().operator[](i);
  }

  StaticArray<Elem> getArray(size_t size) {
    return get().getArray(size);
  }
private:
  ImplWithArray<Impl, Elem> get() {
    return ImplWithArray<Impl, Elem>(&this->getBase());
  }
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class S>
struct SelfTypeInner {
  typedef CustomStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T>
struct SelfTypeInner<T, DefaultStorage<T>> {
  typedef DefaultStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class I, class E>
struct SelfTypeInner<T, ImplWithArray<I, E>> {
  typedef ImplWithArraySelf<T> Self;
};

/**
 * Metafunction from type to its Self type
 * Use as SelfType<T>::Self
 */
template <class T>
struct SelfType {
  typedef typename SelfTypeInner<T, typename Storage<T>::Type>::Self Self;
};

/**
 * Result of the call to a builtin.
 * It always represents a node that must be waited upon. The value 'nullptr' is
 * valid, and denotes that no value must be waited upon, i.e., the execution can
 * continue.
 * Throwing an exception is achieved by pointing to a failed value.
 */
typedef Node* BuiltinResult;

const BuiltinResult BuiltinResultContinue = nullptr;

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class Impl {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(typename SelfType<T>::Self(it), args...);
  }
};

#define IMPL(ResType, Type, method, args...) \
  (Impl<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class ImplNoSelf {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(args...);
  }
};

#define IMPLNOSELF(ResType, Type, method, args...) \
  (ImplNoSelf<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

///////////////
// Reference //
///////////////

class Reference;

template <>
class Storage<Reference> {
public:
  typedef StableNode* Type;
};

template <>
class Implementation<Reference> {
public:
  Implementation<Reference>(StableNode* dest) : _dest(dest) {}
  static StableNode* build(VM, StableNode* dest) { return dest; }

  StableNode* dest() const { return _dest; }
private:
  StableNode* _dest;
};

/**
 * Type of a reference
 */
class Reference: public Type {
public:
  Reference() : Type("Reference", true) {}

  typedef Node* Self;

  static const Reference* const type() {
    static const Reference rawType;
    return &rawType;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally it would have been only a while loop
  static Node& dereference(Node& node) {
    if (node.type != type())
      return node;
    else {
      Node* result = &IMPLNOSELF(StableNode*, Reference, dest, &node)->node;
      if (result->type != type())
        return *result;
      else
        return dereferenceLoop(result);
    }
  }

  static void makeFor(VM vm, UnstableNode& node) {
    StableNode* stable = new (vm) StableNode;
    stable->init(vm, node);
  }

  static void makeFor(VM vm, Node& node) {
    UnstableNode temp;
    temp.node = node;
    makeFor(vm, temp);
    node = temp.node;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally the else case would have been only a while loop
  static StableNode* getStableRefFor(VM vm, Node& node) {
    if (node.type != type()) {
      makeFor(vm, node);
      return IMPLNOSELF(StableNode*, Reference, dest, &node);
    } else {
      StableNode* result = IMPLNOSELF(StableNode*, Reference, dest, &node);
      if (result->node.type != type())
        return result;
      else
        return getStableRefForLoop(result);
    }
  }

  static StableNode* getStableRefFor(VM vm, UnstableNode& node) {
    return getStableRefFor(vm, node.node);
  }

  static StableNode* getStableRefFor(VM vm, StableNode& node) {
    if (node.node.type != type())
      return &node;
    else
      return getStableRefFor(vm, node.node);
  }
private:
  static Node& dereferenceLoop(Node* node) {
    while (node->type == type())
      node = &(IMPLNOSELF(StableNode*, Reference, dest, node)->node);
    return *node;
  }

  static StableNode* getStableRefForLoop(StableNode* node) {
    do {
      node = IMPLNOSELF(StableNode*, Reference, dest, &node->node);
    } while (node->node.type == type());

    return node;
  }

};

/////////////////////////
// Node implementation //
/////////////////////////

void Node::reset(VM vm) {
  type = nullptr;
  value.init<void*>(vm, nullptr);
}

void StableNode::init(VM vm, UnstableNode& from) {
  node = from.node;
  if (!node.type->isCopiable())
    from.make<Reference>(vm, this);
}

void UnstableNode::copy(VM vm, StableNode& from) {
  if (from.node.type->isCopiable())
    node = from.node;
  else
    make<Reference>(vm, &from);
}

void UnstableNode::copy(VM vm, UnstableNode& from) {
  if (!from.node.type->isCopiable())
    Reference::makeFor(vm, from);
  node = from.node;
}

void UnstableNode::reset(VM vm) {
  node.reset(vm);
}

void UnstableNode::swap(UnstableNode& from) {
  Node temp = node;
  node = from.node;
  from.node = temp;
}

#include "vm.hh"

#endif // __STORE_H
<commit_msg>In Nodes, GC-related fields exported in Stable- and UnstableNode instead of Node.<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __STORE_H
#define __STORE_H

#include "core-forward-decl.hh"
#include "memword.hh"
#include "storage.hh"
#include "type.hh"

/**
 * A value node in the store.
 * The store is entirely made of nodes. A node is basically a typed value.
 * Non-atomic values, such as records, contain references to other nodes in the
 * store, hence forming a graph, and the name "node".
 * There are two kinds of node: stable and unstable node. A stable node is
 * guaranteed never to change, whereas unstable node can change. In order to
 * maintain consistency in the store, non-atomic values are only allowed to
 * reference stable nodes. Unstable nodes are used for working data, and
 * inherently mutable data (such as the contents of a cell).
 */
class Node {
public:
  template<class T, class... Args>
  void make(VM vm, Args... args) {
    typedef Accessor<T, typename Storage<T>::Type> Access;
    Access::init(type, value, vm, args...);
  }

  inline void reset(VM vm);

  const Type* type;
  MemWord value;
};

/**
 * Stable node, which is guaranteed never to change
 */
class StableNode {
public:
  inline void init(VM vm, UnstableNode& from);
private:
  friend class UnstableNode;
public: // TODO make it private once the development has been bootstrapped
  union {
    Node node;

    // Garbage collector hack
    struct {
      StableNode* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Unstable node, which is allowed to change over time
 */
class UnstableNode {
public:
  UnstableNode() {}

  UnstableNode(VM vm, StableNode& from) {
    copy(vm, from);
  }

  UnstableNode(VM vm, UnstableNode& from) {
    copy(vm, from);
  }

  inline void copy(VM vm, StableNode& from);
  inline void copy(VM vm, UnstableNode& from);
  inline void swap(UnstableNode& from);
  inline void reset(VM vm);

  template<class T, class... Args>
  void make(VM vm, Args... args) {
    node.make<T>(vm, args...);
  }
private:
  friend class StableNode;
public: // TODO make it private once the development has been bootstrapped
  union {
    Node node;

    // Garbage collector hack
    struct {
      UnstableNode* gcNext;
      Node* gcFrom;
    };
  };
};

/**
 * Base class for Self types
 */
template <class T>
class BaseSelf {
protected:
  typedef typename Storage<T>::Type StorageType;
  typedef Accessor<T, StorageType> Access;
public:
  BaseSelf(Node* node) : _node(node) {}

  template<class U, class... Args>
  void make(VM vm, Args... args) {
    _node->make<U>(vm, args...);
  }

  operator Node*() {
    return _node;
  }

  Node& operator*() {
    return *_node;
  }
protected:
  auto getBase() -> decltype(Access::get(MemWord())) {
    return Access::get(_node->value);
  }

  Node* _node;
};

/**
 * Self type for custom storage-based types
 */
template <class T>
class CustomStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  CustomStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl get() {
    return this->getBase();
  }
};

/**
 * Self type for default storage-based types
 */
template <class T>
class DefaultStorageSelf: public BaseSelf<T> {
private:
  typedef Implementation<T> Impl;
public:
  DefaultStorageSelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return &this->getBase();
  }
};

/**
 * Extractor function for the template parameters of ImplWithArray
 * Given
 *   typedef ImplWithArray<I, E> T;
 * this provides
 *   ExtractImplWithArray<T>::Impl === I
 *   ExtractImplWithArray<T>::Elem === E
 */
template <class S>
struct ExtractImplWithArray {};

template <class I, class E>
struct ExtractImplWithArray<ImplWithArray<I, E>> {
  typedef I Impl;
  typedef E Elem;
};

/**
 * Self type for ImplWithArray-based types
 */
template <class T>
class ImplWithArraySelf: public BaseSelf<T> {
private:
  typedef typename BaseSelf<T>::StorageType StorageType;
  typedef typename ExtractImplWithArray<StorageType>::Impl Impl;
  typedef typename ExtractImplWithArray<StorageType>::Elem Elem;
public:
  ImplWithArraySelf(Node* node) : BaseSelf<T>(node) {}

  Impl* operator->() {
    return get().operator->();
  }

  Elem& operator[](size_t i) {
    return get().operator[](i);
  }

  StaticArray<Elem> getArray(size_t size) {
    return get().getArray(size);
  }
private:
  ImplWithArray<Impl, Elem> get() {
    return ImplWithArray<Impl, Elem>(&this->getBase());
  }
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class S>
struct SelfTypeInner {
  typedef CustomStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T>
struct SelfTypeInner<T, DefaultStorage<T>> {
  typedef DefaultStorageSelf<T> Self;
};

/**
 * Helper for the metafunction SelfType
 */
template <class T, class I, class E>
struct SelfTypeInner<T, ImplWithArray<I, E>> {
  typedef ImplWithArraySelf<T> Self;
};

/**
 * Metafunction from type to its Self type
 * Use as SelfType<T>::Self
 */
template <class T>
struct SelfType {
  typedef typename SelfTypeInner<T, typename Storage<T>::Type>::Self Self;
};

/**
 * Result of the call to a builtin.
 * It always represents a node that must be waited upon. The value 'nullptr' is
 * valid, and denotes that no value must be waited upon, i.e., the execution can
 * continue.
 * Throwing an exception is achieved by pointing to a failed value.
 */
typedef Node* BuiltinResult;

const BuiltinResult BuiltinResultContinue = nullptr;

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class Impl {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(typename SelfType<T>::Self(it), args...);
  }
};

#define IMPL(ResType, Type, method, args...) \
  (Impl<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

/**
 * Strange and magical class that allows to call methods on storage-typed nodes
 */
template<class T, class R, class M, M m>
class ImplNoSelf {
public:
  typedef Accessor<T, typename Storage<T>::Type> Type;

  template<class... Args>
  static R f(Node* it, Args... args) {
    return (Type::get(it->value).*m)(args...);
  }
};

#define IMPLNOSELF(ResType, Type, method, args...) \
  (ImplNoSelf<Type, ResType, decltype(&Implementation<Type>::method), \
    &Implementation<Type>::method>::f(args))

///////////////
// Reference //
///////////////

class Reference;

template <>
class Storage<Reference> {
public:
  typedef StableNode* Type;
};

template <>
class Implementation<Reference> {
public:
  Implementation<Reference>(StableNode* dest) : _dest(dest) {}
  static StableNode* build(VM, StableNode* dest) { return dest; }

  StableNode* dest() const { return _dest; }
private:
  StableNode* _dest;
};

/**
 * Type of a reference
 */
class Reference: public Type {
public:
  Reference() : Type("Reference", true) {}

  typedef Node* Self;

  static const Reference* const type() {
    static const Reference rawType;
    return &rawType;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally it would have been only a while loop
  static Node& dereference(Node& node) {
    if (node.type != type())
      return node;
    else {
      Node* result = &IMPLNOSELF(StableNode*, Reference, dest, &node)->node;
      if (result->type != type())
        return *result;
      else
        return dereferenceLoop(result);
    }
  }

  static void makeFor(VM vm, UnstableNode& node) {
    StableNode* stable = new (vm) StableNode;
    stable->init(vm, node);
  }

  static void makeFor(VM vm, Node& node) {
    UnstableNode temp;
    temp.node = node;
    makeFor(vm, temp);
    node = temp.node;
  }

  // This is optimized for the 0- and 1-dereference paths
  // Normally the else case would have been only a while loop
  static StableNode* getStableRefFor(VM vm, Node& node) {
    if (node.type != type()) {
      makeFor(vm, node);
      return IMPLNOSELF(StableNode*, Reference, dest, &node);
    } else {
      StableNode* result = IMPLNOSELF(StableNode*, Reference, dest, &node);
      if (result->node.type != type())
        return result;
      else
        return getStableRefForLoop(result);
    }
  }

  static StableNode* getStableRefFor(VM vm, UnstableNode& node) {
    return getStableRefFor(vm, node.node);
  }

  static StableNode* getStableRefFor(VM vm, StableNode& node) {
    if (node.node.type != type())
      return &node;
    else
      return getStableRefFor(vm, node.node);
  }
private:
  static Node& dereferenceLoop(Node* node) {
    while (node->type == type())
      node = &(IMPLNOSELF(StableNode*, Reference, dest, node)->node);
    return *node;
  }

  static StableNode* getStableRefForLoop(StableNode* node) {
    do {
      node = IMPLNOSELF(StableNode*, Reference, dest, &node->node);
    } while (node->node.type == type());

    return node;
  }

};

/////////////////////////
// Node implementation //
/////////////////////////

void Node::reset(VM vm) {
  type = nullptr;
  value.init<void*>(vm, nullptr);
}

void StableNode::init(VM vm, UnstableNode& from) {
  node = from.node;
  if (!node.type->isCopiable())
    from.make<Reference>(vm, this);
}

void UnstableNode::copy(VM vm, StableNode& from) {
  if (from.node.type->isCopiable())
    node = from.node;
  else
    make<Reference>(vm, &from);
}

void UnstableNode::copy(VM vm, UnstableNode& from) {
  if (!from.node.type->isCopiable())
    Reference::makeFor(vm, from);
  node = from.node;
}

void UnstableNode::reset(VM vm) {
  node.reset(vm);
}

void UnstableNode::swap(UnstableNode& from) {
  Node temp = node;
  node = from.node;
  from.node = temp;
}

#include "vm.hh"

#endif // __STORE_H
<|endoftext|>


<commit_before>#include "VoiceDB.h"

using namespace std;

VoiceDB::VoiceDB():path_singer("") {}

VoiceDB::VoiceDB(string path_singer)
{
  setSingerPath(path_singer);
}

VoiceDB::~VoiceDB() {}

bool VoiceDB::initVoiceMap()
{
  namespace fs = boost::filesystem;
  const fs::path path(path_singer);

  if (fs::is_directory(path)) {
    BOOST_FOREACH(const fs::path& p, std::make_pair(fs::recursive_directory_iterator(path), fs::recursive_directory_iterator())) {
      if (p.leaf().string() == "oto.ini") {
        cout << "loading " << p.string() << endl;
        initVoiceMap(p.string());
      }
    }
    if (voice_map.size() > 0)
      return true;
  }

  cerr << "[VoiceDB::initVoiceMap] path_singer is invalid" << endl;
  return false;
}

bool VoiceDB::initVoiceMap(string path_oto_ini)
{
  ifstream ifs(path_oto_ini.c_str());
  boost::filesystem::path path_ini(path_oto_ini);
  string buf, wav_ext=".wav";
  while(ifs && getline(ifs, buf)) {
    // read oto.ini
    Voice tmp_voice(this);
    vector<string> v1, v2;
    boost::algorithm::split(v1, buf, boost::is_any_of("="));
    boost::algorithm::split(v2, v1[1], boost::is_any_of(","));
    short tmp;
    tmp_voice.setWavPath(path_ini.parent_path().string()+"/"+v1[0]);
    tmp_voice.offs = (((tmp=boost::lexical_cast<double>(v2[1]))>0))?tmp:0;
    tmp_voice.cons = (((tmp=boost::lexical_cast<double>(v2[2]))>0))?tmp:0;
    tmp_voice.blnk = boost::lexical_cast<double>(v2[3]);
    tmp_voice.prec = boost::lexical_cast<double>(v2[4]);
    tmp_voice.ovrl = boost::lexical_cast<double>(v2[5]);
    tmp_voice.is_vcv = false;
    // sanitize
    if (tmp_voice.ovrl < 0) {
      tmp_voice.ovrl *= -1;
      tmp_voice.offs -= tmp_voice.ovrl;
      tmp_voice.cons += tmp_voice.ovrl;
      tmp_voice.prec += tmp_voice.ovrl;
      if (tmp_voice.blnk < 0) {
        tmp_voice.blnk -= tmp_voice.ovrl;
      }
    }
    if (tmp_voice.ovrl > tmp_voice.prec) {
      tmp_voice.prec = tmp_voice.ovrl;
    }
    if (tmp_voice.prec > tmp_voice.cons) {
      tmp_voice.cons = tmp_voice.prec;
    }
    if (tmp_voice.blnk<0 && tmp_voice.cons > -tmp_voice.blnk) {
      tmp_voice.blnk = -tmp_voice.cons;
    }
    // get Voice pron
    {
      string tmp_alias = (v2[0]=="")?tmp_voice.path_wav.stem().string():v2[0];
      tmp_voice.pron = tmp_voice.prefix = tmp_voice.suffix = "";
      // get prefix
      string::size_type pos_prefix = tmp_alias.find(" ");
      if (tmp_alias.size()>1 && pos_prefix != string::npos) {
        tmp_voice.prefix = tmp_alias.substr(0, pos_prefix+1);
        tmp_alias.erase(0, pos_prefix+1);
        if (tmp_voice.prefix!="- " && tmp_voice.prefix!="* ") {
          tmp_voice.is_vcv = true;
        }
      }
      // get suffix
      if (tmp_alias.size() > 2) {
        string tmp_suffix = tmp_alias.substr(tmp_alias.size()-2);
        if (isalpha(tmp_suffix[0]) && isdigit(tmp_suffix[1])) {
          tmp_voice.suffix = tmp_suffix;
          tmp_alias.erase(tmp_alias.size()-2, 2);
        }
      }
      tmp_voice.pron = tmp_alias;
    }
    // set vowel_map
    if (!tmp_voice.is_vcv) {
      map<string, string>::const_iterator it = nak::getVow2PronIt(tmp_voice.pron);
      if (it!=nak::vow2pron.end()) {
        WavParser wav_parser(tmp_voice.path_wav.string());
        wav_parser.addTargetTrack(0);
        if (wav_parser.parse()) {
          vector<short> tmp_wav = (*(wav_parser.getDataChunks().begin())).getDataVector();
          vector<short>::iterator it_tmp_wav_cons = tmp_wav.begin()+((tmp_voice.offs+tmp_voice.cons)/1000.0*wav_parser.getFormat().dwSamplesPerSec);
          vector<short>::iterator it_tmp_wav_min = it_tmp_wav_cons;
          short win_size = wav_parser.getFormat().dwSamplesPerSec / tmp_voice.getFrq();
          double tmp_min_rms = -1.0;
          for (int i=0; i<win_size*2; i++) {
            vector<short> tmp_wav(it_tmp_wav_cons+i-win_size, it_tmp_wav_cons+i+win_size);
            double tmp_rms = nak::getRMS(tmp_wav);
            if (tmp_rms<tmp_min_rms || tmp_min_rms<0) {
              tmp_min_rms = tmp_rms;
              it_tmp_wav_min = it_tmp_wav_cons+i;
            }
          }
          vowel_map[nak::pron2vow[it->second]+tmp_voice.suffix].assign(it_tmp_wav_min-win_size, it_tmp_wav_min+win_size);
        }
      }
    }
    voice_map[tmp_voice.pron] = tmp_voice;
  }
  return true;
}

const Voice* VoiceDB::getVoice(string alias)
{
  if (!isAlias(alias))
    return 0;

  return &voice_map[alias];
}

bool VoiceDB::isAlias(string alias)
{
  return !((voice_map.empty()&&!initVoiceMap()) || voice_map.count(alias)==0);
}

bool VoiceDB::isVowel(string alias)
{
  return vowel_map.count(alias)>0;
}

vector<short> VoiceDB::getVowel(string alias)
{
  return vowel_map[alias];
}

void VoiceDB::setSingerPath(string path_singer)
{
  this->path_singer = path_singer;
}

string VoiceDB::getSingerPath()
{
  return this->path_singer;
}
<commit_msg>bugfix<commit_after>#include "VoiceDB.h"

using namespace std;

VoiceDB::VoiceDB():path_singer("") {}

VoiceDB::VoiceDB(string path_singer)
{
  setSingerPath(path_singer);
}

VoiceDB::~VoiceDB() {}

bool VoiceDB::initVoiceMap()
{
  namespace fs = boost::filesystem;
  const fs::path path(path_singer);

  if (fs::is_directory(path)) {
    BOOST_FOREACH(const fs::path& p, std::make_pair(fs::recursive_directory_iterator(path), fs::recursive_directory_iterator())) {
      if (p.leaf().string() == "oto.ini") {
        cout << "loading " << p.string() << endl;
        initVoiceMap(p.string());
      }
    }
    if (voice_map.size() > 0)
      return true;
  }

  cerr << "[VoiceDB::initVoiceMap] path_singer is invalid" << endl;
  return false;
}

bool VoiceDB::initVoiceMap(string path_oto_ini)
{
  ifstream ifs(path_oto_ini.c_str());
  boost::filesystem::path path_ini(path_oto_ini);
  string buf, wav_ext=".wav";
  while(ifs && getline(ifs, buf)) {
    // read oto.ini
    Voice tmp_voice(this);
    vector<string> v1, v2;
    boost::algorithm::split(v1, buf, boost::is_any_of("="));
    boost::algorithm::split(v2, v1[1], boost::is_any_of(","));
    short tmp;
    tmp_voice.setWavPath(path_ini.parent_path().string()+"/"+v1[0]);
    tmp_voice.offs = (((tmp=boost::lexical_cast<double>(v2[1]))>0))?tmp:0;
    tmp_voice.cons = (((tmp=boost::lexical_cast<double>(v2[2]))>0))?tmp:0;
    tmp_voice.blnk = boost::lexical_cast<double>(v2[3]);
    tmp_voice.prec = boost::lexical_cast<double>(v2[4]);
    tmp_voice.ovrl = boost::lexical_cast<double>(v2[5]);
    tmp_voice.is_vcv = false;
    // sanitize
    if (tmp_voice.ovrl < 0) {
      tmp_voice.ovrl *= -1;
      tmp_voice.offs -= tmp_voice.ovrl;
      tmp_voice.cons += tmp_voice.ovrl;
      tmp_voice.prec += tmp_voice.ovrl;
      if (tmp_voice.blnk < 0) {
        tmp_voice.blnk -= tmp_voice.ovrl;
      }
    }
    if (tmp_voice.ovrl > tmp_voice.prec) {
      tmp_voice.prec = tmp_voice.ovrl;
    }
    if (tmp_voice.prec > tmp_voice.cons) {
      tmp_voice.cons = tmp_voice.prec;
    }
    if (tmp_voice.blnk<0 && tmp_voice.cons > -tmp_voice.blnk) {
      tmp_voice.blnk = -tmp_voice.cons;
    }
    // get Voice pron
    {
      string tmp_alias = (v2[0]=="")?tmp_voice.path_wav.stem().string():v2[0];
      tmp_voice.pron = tmp_voice.prefix = tmp_voice.suffix = "";
      // get prefix
      string::size_type pos_prefix = tmp_alias.find(" ");
      if (tmp_alias.size()>1 && pos_prefix != string::npos) {
        tmp_voice.prefix = tmp_alias.substr(0, pos_prefix+1);
        tmp_alias.erase(0, pos_prefix+1);
        if (tmp_voice.prefix!="- " && tmp_voice.prefix!="* ") {
          tmp_voice.is_vcv = true;
        }
      }
      // get suffix
      if (tmp_alias.size() > 2) {
        string tmp_suffix = tmp_alias.substr(tmp_alias.size()-2);
        if (isalpha(tmp_suffix[0]) && isdigit(tmp_suffix[1])) {
          tmp_voice.suffix = tmp_suffix;
          tmp_alias.erase(tmp_alias.size()-2, 2);
        }
      }
      tmp_voice.pron = tmp_alias;
    }
    // set vowel_map
    if (!tmp_voice.is_vcv) {
      map<string, string>::const_iterator it = nak::getVow2PronIt(tmp_voice.pron);
      if (it!=nak::vow2pron.end()) {
        WavParser wav_parser(tmp_voice.path_wav.string());
        wav_parser.addTargetTrack(0);
        if (wav_parser.parse()) {
          vector<short> tmp_wav = (*(wav_parser.getDataChunks().begin())).getDataVector();
          vector<short>::iterator it_tmp_wav_cons = tmp_wav.begin()+((tmp_voice.offs+tmp_voice.cons)/1000.0*wav_parser.getFormat().dwSamplesPerSec);
          vector<short>::iterator it_tmp_wav_min = it_tmp_wav_cons;
          short win_size = wav_parser.getFormat().dwSamplesPerSec / tmp_voice.getFrq();
          double tmp_min_rms = -1.0;
          for (int i=0; i<win_size*2; i++) {
            vector<short> tmp_wav(it_tmp_wav_cons+i-win_size, it_tmp_wav_cons+i+win_size);
            double tmp_rms = nak::getRMS(tmp_wav);
            if (tmp_rms<tmp_min_rms || tmp_min_rms<0) {
              tmp_min_rms = tmp_rms;
              it_tmp_wav_min = it_tmp_wav_cons+i;
            }
          }
          vowel_map[nak::pron2vow[it->second]+tmp_voice.suffix].assign(it_tmp_wav_min-win_size, it_tmp_wav_min+win_size);
        }
      }
    }
    voice_map[tmp_voice.prefix+tmp_voice.pron+tmp_voice.suffix] = tmp_voice;
  }
  return true;
}

const Voice* VoiceDB::getVoice(string alias)
{
  if (!isAlias(alias))
    return 0;

  return &voice_map[alias];
}

bool VoiceDB::isAlias(string alias)
{
  return !((voice_map.empty()&&!initVoiceMap()) || voice_map.count(alias)==0);
}

bool VoiceDB::isVowel(string alias)
{
  return vowel_map.count(alias)>0;
}

vector<short> VoiceDB::getVowel(string alias)
{
  return vowel_map[alias];
}

void VoiceDB::setSingerPath(string path_singer)
{
  this->path_singer = path_singer;
}

string VoiceDB::getSingerPath()
{
  return this->path_singer;
}
<|endoftext|>


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

#include <vos/pipe.hxx>
#include <vos/diagnose.hxx>

using namespace vos;

///////////////////////////////////////////////////////////////////////////////
// Pipe

VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OPipe, vos),
                        VOS_NAMESPACE(OPipe, vos),
                        VOS_NAMESPACE(OObject, vos), 0);

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe()
{
    m_pPipeRef= 0;
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/

OPipe::OPipe( const rtl::OUString& strName, TPipeOption Options)
{
    m_pPipeRef =
        new PipeRef( osl_createPipe(strName.pData,
                                    (oslPipeOptions)Options,
                                    NULL) );

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");
    VOS_POSTCOND((*m_pPipeRef)(), "OPipe(): creation of pipe failed!\n");
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/

OPipe::OPipe( const rtl::OUString& strName,
              TPipeOption Options,
              const OSecurity& rSecurity)
{
    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   (oslSecurity)rSecurity));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");
    VOS_POSTCOND((*m_pPipeRef)(), "OPipe(): creation of pipe failed!\n");
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe(const OPipe& pipe)
{

    VOS_ASSERT(pipe.m_pPipeRef != 0);

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe(oslPipe Pipe)
{
    m_pPipeRef = new PipeRef(Pipe);
}

/*****************************************************************************/
// ~OPipe()
/*****************************************************************************/
OPipe::~OPipe()
{
    close();
}

/*****************************************************************************/
// create
/*****************************************************************************/
sal_Bool OPipe::create( const rtl::OUString& strName, TPipeOption Options )
{
    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   NULL));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// create
/*****************************************************************************/
sal_Bool OPipe::create( const rtl::OUString& strName,
                        TPipeOption Options,
                        const NAMESPACE_VOS(OSecurity)& rSecurity )
{
    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   (oslSecurity)rSecurity));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// operator=
/*****************************************************************************/
OPipe& OPipe::operator= (const OPipe& pipe)
{
    VOS_PRECOND(pipe.m_pPipeRef != 0, "OPipe::operator=: tried to assign an empty/invalid pipe\n");

    if (m_pPipeRef == pipe.m_pPipeRef)
        return *this;

    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();

    return *this;
}

/*****************************************************************************/
// operator oslPipe()
/*****************************************************************************/
OPipe::operator oslPipe() const
{
    VOS_ASSERT(m_pPipeRef);
    return (*m_pPipeRef)();
}

/*****************************************************************************/
// isValid()
/*****************************************************************************/
sal_Bool OPipe::isValid() const
{
    return m_pPipeRef != 0 && (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// close
/*****************************************************************************/
void OPipe::close()
{
    if (m_pPipeRef && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
    }
    m_pPipeRef= 0;
}

/*****************************************************************************/
// accept
/*****************************************************************************/
OPipe::TPipeError OPipe::accept(OStreamPipe& Connection)
{
    if ( isValid() )
    {
        Connection = osl_acceptPipe((*m_pPipeRef)());

        if(Connection.isValid())
            return E_None;
    }

    return getError();
}

/*****************************************************************************/
// recv
/*****************************************************************************/
sal_Int32 OPipe::recv(void* pBuffer, sal_uInt32 BytesToRead)
{
    if ( isValid() )
        return osl_receivePipe((*m_pPipeRef)(),
                             pBuffer,
                            BytesToRead);
    else
        return -1;

}

/*****************************************************************************/
// send
/*****************************************************************************/
sal_Int32 OPipe::send(const void* pBuffer, sal_uInt32 BytesToSend)
{
    if ( isValid() )
        return osl_sendPipe((*m_pPipeRef)(),
                            pBuffer,
                            BytesToSend);
    else
        return -1;
}

/*****************************************************************************/
// getError
/*****************************************************************************/
OPipe::TPipeError OPipe::getError() const
{
    if (m_pPipeRef)
        return (TPipeError)osl_getLastPipeError((*m_pPipeRef)());
    else
        return (TPipeError)osl_getLastPipeError(NULL);
}

VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OStreamPipe, vos),
                        VOS_NAMESPACE(OStreamPipe, vos),
                        VOS_NAMESPACE(OPipe, vos), 0);

/*****************************************************************************/
// OStreamPipe
/*****************************************************************************/
OStreamPipe::OStreamPipe()
{
}

/*****************************************************************************/
// OStreamPipe
/*****************************************************************************/
OStreamPipe::OStreamPipe(oslPipe Pipe) :
    OPipe(Pipe)
{
}

/*****************************************************************************/
// OStreamPipe
// copy constructor
/*****************************************************************************/
OStreamPipe::OStreamPipe(const OStreamPipe& pipe)
{
    VOS_ASSERT(pipe.m_pPipeRef != 0);

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();
}

/*****************************************************************************/
// ~OStreamPipe
/*****************************************************************************/
OStreamPipe::~OStreamPipe()
{
}

/*****************************************************************************/
// operator=(oslPipe)
/*****************************************************************************/
OStreamPipe& OStreamPipe::operator=(oslPipe Pipe)
{

    // if this was a valid pipe, decrease reference
    if (m_pPipeRef && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef= new PipeRef(Pipe);

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return *this;
}

/*****************************************************************************/
// operator=OPipe
/*****************************************************************************/

OStreamPipe& OStreamPipe::operator= (const OPipe& pipe)
{
    OPipe::operator= ( pipe );
    return *this;
}

/*****************************************************************************/
// read
/*****************************************************************************/
sal_Int32 OStreamPipe::read(void* pBuffer, sal_uInt32 n) const
{
    VOS_ASSERT(m_pPipeRef && (*m_pPipeRef)());

    /* loop until all desired bytes were read or an error occured */
    sal_Int32 BytesRead= 0;
    sal_Int32 BytesToRead= n;
    while (BytesToRead > 0)
    {
        sal_Int32 RetVal;
        RetVal= osl_receivePipe((*m_pPipeRef)(),
                                 pBuffer,
                                BytesToRead);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToRead -= RetVal;
        BytesRead += RetVal;
        pBuffer= (sal_Char*)pBuffer + RetVal;
    }

    return BytesRead;
}

/*****************************************************************************/
// write
/*****************************************************************************/
sal_Int32 OStreamPipe::write(const void* pBuffer, sal_uInt32 n)
{
    VOS_ASSERT(m_pPipeRef && (*m_pPipeRef)());

    /* loop until all desired bytes were send or an error occured */
    sal_Int32 BytesSend= 0;
    sal_Int32 BytesToSend= n;
    while (BytesToSend > 0)
    {
        sal_Int32 RetVal;

        RetVal= osl_sendPipe((*m_pPipeRef)(),
                                pBuffer,
                                BytesToSend);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToSend -= RetVal;
        BytesSend += RetVal;
        pBuffer= (sal_Char*)pBuffer + RetVal;
    }

    return BytesSend;
}

sal_Bool OStreamPipe::isEof() const
{
    return isValid();
}

<commit_msg>INTEGRATION: CWS warnings01 (1.4.4); FILE MERGED 2005/11/09 12:16:38 pl 1.4.4.1: #i53898# removed warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pipe.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 04:07:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <vos/pipe.hxx>
#include <vos/diagnose.hxx>

using namespace vos;

///////////////////////////////////////////////////////////////////////////////
// Pipe

VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OPipe, vos),
                        VOS_NAMESPACE(OPipe, vos),
                        VOS_NAMESPACE(OObject, vos), 0);

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe()
{
    m_pPipeRef= 0;
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/

OPipe::OPipe( const rtl::OUString& strName, TPipeOption Options)
{
    m_pPipeRef =
        new PipeRef( osl_createPipe(strName.pData,
                                    (oslPipeOptions)Options,
                                    NULL) );

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");
    VOS_POSTCOND((*m_pPipeRef)(), "OPipe(): creation of pipe failed!\n");
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/

OPipe::OPipe( const rtl::OUString& strName,
              TPipeOption Options,
              const OSecurity& rSecurity)
{
    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   (oslSecurity)rSecurity));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");
    VOS_POSTCOND((*m_pPipeRef)(), "OPipe(): creation of pipe failed!\n");
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe(const OPipe& pipe) :
OReference(), OObject()
{

    VOS_ASSERT(pipe.m_pPipeRef != 0);

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();
}

/*****************************************************************************/
// OPipe()
/*****************************************************************************/
OPipe::OPipe(oslPipe Pipe)
{
    m_pPipeRef = new PipeRef(Pipe);
}

/*****************************************************************************/
// ~OPipe()
/*****************************************************************************/
OPipe::~OPipe()
{
    close();
}

/*****************************************************************************/
// create
/*****************************************************************************/
sal_Bool OPipe::create( const rtl::OUString& strName, TPipeOption Options )
{
    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   NULL));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// create
/*****************************************************************************/
sal_Bool OPipe::create( const rtl::OUString& strName,
                        TPipeOption Options,
                        const NAMESPACE_VOS(OSecurity)& rSecurity )
{
    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef=
        new PipeRef(osl_createPipe(strName.pData,
                                   (oslPipeOptions)Options,
                                   (oslSecurity)rSecurity));

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// operator=
/*****************************************************************************/
OPipe& OPipe::operator= (const OPipe& pipe)
{
    VOS_PRECOND(pipe.m_pPipeRef != 0, "OPipe::operator=: tried to assign an empty/invalid pipe\n");

    if (m_pPipeRef == pipe.m_pPipeRef)
        return *this;

    // if this was a valid pipe, decrease reference
    if ((m_pPipeRef) && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();

    return *this;
}

/*****************************************************************************/
// operator oslPipe()
/*****************************************************************************/
OPipe::operator oslPipe() const
{
    VOS_ASSERT(m_pPipeRef);
    return (*m_pPipeRef)();
}

/*****************************************************************************/
// isValid()
/*****************************************************************************/
sal_Bool OPipe::isValid() const
{
    return m_pPipeRef != 0 && (*m_pPipeRef)() != 0;
}

/*****************************************************************************/
// close
/*****************************************************************************/
void OPipe::close()
{
    if (m_pPipeRef && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
    }
    m_pPipeRef= 0;
}

/*****************************************************************************/
// accept
/*****************************************************************************/
OPipe::TPipeError OPipe::accept(OStreamPipe& Connection)
{
    if ( isValid() )
    {
        Connection = osl_acceptPipe((*m_pPipeRef)());

        if(Connection.isValid())
            return E_None;
    }

    return getError();
}

/*****************************************************************************/
// recv
/*****************************************************************************/
sal_Int32 OPipe::recv(void* pBuffer, sal_uInt32 BytesToRead)
{
    if ( isValid() )
        return osl_receivePipe((*m_pPipeRef)(),
                             pBuffer,
                            BytesToRead);
    else
        return -1;

}

/*****************************************************************************/
// send
/*****************************************************************************/
sal_Int32 OPipe::send(const void* pBuffer, sal_uInt32 BytesToSend)
{
    if ( isValid() )
        return osl_sendPipe((*m_pPipeRef)(),
                            pBuffer,
                            BytesToSend);
    else
        return -1;
}

/*****************************************************************************/
// getError
/*****************************************************************************/
OPipe::TPipeError OPipe::getError() const
{
    if (m_pPipeRef)
        return (TPipeError)osl_getLastPipeError((*m_pPipeRef)());
    else
        return (TPipeError)osl_getLastPipeError(NULL);
}

VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OStreamPipe, vos),
                        VOS_NAMESPACE(OStreamPipe, vos),
                        VOS_NAMESPACE(OPipe, vos), 0);

/*****************************************************************************/
// OStreamPipe
/*****************************************************************************/
OStreamPipe::OStreamPipe()
{
}

/*****************************************************************************/
// OStreamPipe
/*****************************************************************************/
OStreamPipe::OStreamPipe(oslPipe Pipe) :
    OPipe(Pipe)
{
}

/*****************************************************************************/
// OStreamPipe
// copy constructor
/*****************************************************************************/
OStreamPipe::OStreamPipe(const OStreamPipe& pipe) :
OPipe(), IStream()
{
    VOS_ASSERT(pipe.m_pPipeRef != 0);

    m_pPipeRef= pipe.m_pPipeRef;

    m_pPipeRef->acquire();
}

/*****************************************************************************/
// ~OStreamPipe
/*****************************************************************************/
OStreamPipe::~OStreamPipe()
{
}

/*****************************************************************************/
// operator=(oslPipe)
/*****************************************************************************/
OStreamPipe& OStreamPipe::operator=(oslPipe Pipe)
{

    // if this was a valid pipe, decrease reference
    if (m_pPipeRef && (m_pPipeRef->release() == 0))
    {
        osl_releasePipe((*m_pPipeRef)());
        delete m_pPipeRef;
        m_pPipeRef= 0;
    }

    m_pPipeRef= new PipeRef(Pipe);

    VOS_POSTCOND(m_pPipeRef != 0, "OPipe(): new failed.\n");

    return *this;
}

/*****************************************************************************/
// operator=OPipe
/*****************************************************************************/

OStreamPipe& OStreamPipe::operator= (const OPipe& pipe)
{
    OPipe::operator= ( pipe );
    return *this;
}

/*****************************************************************************/
// read
/*****************************************************************************/
sal_Int32 OStreamPipe::read(void* pBuffer, sal_uInt32 n) const
{
    VOS_ASSERT(m_pPipeRef && (*m_pPipeRef)());

    /* loop until all desired bytes were read or an error occured */
    sal_Int32 BytesRead= 0;
    sal_Int32 BytesToRead= n;
    while (BytesToRead > 0)
    {
        sal_Int32 RetVal;
        RetVal= osl_receivePipe((*m_pPipeRef)(),
                                 pBuffer,
                                BytesToRead);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToRead -= RetVal;
        BytesRead += RetVal;
        pBuffer= (sal_Char*)pBuffer + RetVal;
    }

    return BytesRead;
}

/*****************************************************************************/
// write
/*****************************************************************************/
sal_Int32 OStreamPipe::write(const void* pBuffer, sal_uInt32 n)
{
    VOS_ASSERT(m_pPipeRef && (*m_pPipeRef)());

    /* loop until all desired bytes were send or an error occured */
    sal_Int32 BytesSend= 0;
    sal_Int32 BytesToSend= n;
    while (BytesToSend > 0)
    {
        sal_Int32 RetVal;

        RetVal= osl_sendPipe((*m_pPipeRef)(),
                                pBuffer,
                                BytesToSend);

        /* error occured? */
        if(RetVal <= 0)
        {
            break;
        }

        BytesToSend -= RetVal;
        BytesSend += RetVal;
        pBuffer= (sal_Char*)pBuffer + RetVal;
    }

    return BytesSend;
}

sal_Bool OStreamPipe::isEof() const
{
    return isValid();
}

<|endoftext|>


<commit_before>// -------------------------------------------------------------------
//
// db_list.cc
//
// Copyright (c) 2011-2013 Basho Technologies, Inc. All Rights Reserved.
//
// This file is provided to you 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 <algorithm>
#include <syslog.h>

#include "util/db_list.h"
#include "util/mutexlock.h"

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

namespace leveldb {

// using singleton model from comparator.cc
static port::OnceType once = LEVELDB_ONCE_INIT;
static DBListImpl * dblist=NULL;

static void InitModule()
{
    dblist=new DBListImpl;
}   // InitModule

DBListImpl * DBList()
{
    port::InitOnce(&once, InitModule);
    return(dblist);

}   // DBList

void
DBListShutdown()
{
    // retrieve point to handle any initialization/shutdown races
    DBList();
    delete dblist;

    return;

}   // DBListShutdown

DBListImpl::DBListImpl()
{
}   // DBListImpl::DBListImpl

bool
DBListImpl::AddDB(
    DBImpl * Dbase,
    bool IsInternal)
{
    bool ret_flag;

    SpinLock lock(&m_Lock);

    if (IsInternal)
    {
        ret_flag=m_InternalDBs.insert(Dbase).second;
        m_InternalDBCount=m_InternalDBs.size();
    }   // if
    else
    {
        ret_flag=m_UserDBs.insert(Dbase).second;
        m_UserDBCount=m_UserDBs.size();
    }   // else

    return(ret_flag);

}   // DBListImpl::AddDB

void
DBListImpl::ReleaseDB(
    DBImpl * Dbase,
    bool IsInternal)
{
    db_set_t::iterator it;
    SpinLock lock(&m_Lock);

    if (IsInternal)
    {
        it=m_InternalDBs.find(Dbase);
        if (m_InternalDBs.end()!=it)
        {
            m_InternalDBs.erase(it);
        }   // if
        m_InternalDBCount=m_InternalDBs.size();
    }   // if
    else
    {
        it=m_UserDBs.find(Dbase);
        if (m_UserDBs.end()!=it)
        {
            m_UserDBs.erase(it);
        }   // if
        m_UserDBCount=m_UserDBs.size();
    }   // else

    return;

}   // DBListImpl::ReleaseDB

size_t
DBListImpl::GetDBCount(
    bool IsInternal)
{
    size_t ret_val;

    if (IsInternal)
        ret_val=m_InternalDBCount;
    else
        ret_val=m_UserDBCount;

    return(ret_val);

}   // DBListImpl::GetDBCount

void
DBListImpl::ScanDBs(
    bool IsInternal,
    void (DBImpl::* Function)())
{
    db_set_t::iterator it, first, last;
    SpinLock lock(&m_Lock);

    size_t count;

    // for_each() would have been fun, but setup deadlock
    //  scenarios
    // Now we have a race condition of us using the db object
    //  while someone is shutting it down ... hmm
    if (IsInternal)
    {
        first=m_InternalDBs.begin();
        last=m_InternalDBs.end();
        count=m_InternalDBs.size();
    }   // if
    else
    {
        first=m_UserDBs.begin();
        last=m_UserDBs.end();
        count=m_UserDBs.size();
    }   // else

#if 0  // for debugging ... sometimes
    m_Lock.Unlock(); /// might not be needed now
    syslog(LOG_ERR, "count %zd, total memory %" PRIu64 ", db cache size %" PRIu64 ", internal %d",
           count, gFlexCache.GetTotalMemory(), gFlexCache.GetDBCacheCapacity(IsInternal),
           (int)IsInternal);
    m_Lock.Lock();
#endif

    // call member function of each database
    for (it=first; last!=it; ++it)
    {
        // must protect list from db add/delete during scan, leave locks
//        m_Lock.Unlock();
        ((*it)->*Function)();
//        m_Lock.Lock();
    }   // for

    return;

}   // DBListImpl::ScanDBs

}  // namespace leveldb
<commit_msg>clean up compiler warning and remove two dead code lines<commit_after>// -------------------------------------------------------------------
//
// db_list.cc
//
// Copyright (c) 2011-2013 Basho Technologies, Inc. All Rights Reserved.
//
// This file is provided to you 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 <algorithm>
#include <syslog.h>

#include "util/db_list.h"
#include "util/mutexlock.h"

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

namespace leveldb {

// using singleton model from comparator.cc
static port::OnceType once = LEVELDB_ONCE_INIT;
static DBListImpl * dblist=NULL;

static void InitModule()
{
    dblist=new DBListImpl;
}   // InitModule

DBListImpl * DBList()
{
    port::InitOnce(&once, InitModule);
    return(dblist);

}   // DBList

void
DBListShutdown()
{
    // retrieve point to handle any initialization/shutdown races
    DBList();
    delete dblist;

    return;

}   // DBListShutdown

DBListImpl::DBListImpl()
{
}   // DBListImpl::DBListImpl

bool
DBListImpl::AddDB(
    DBImpl * Dbase,
    bool IsInternal)
{
    bool ret_flag;

    SpinLock lock(&m_Lock);

    if (IsInternal)
    {
        ret_flag=m_InternalDBs.insert(Dbase).second;
        m_InternalDBCount=m_InternalDBs.size();
    }   // if
    else
    {
        ret_flag=m_UserDBs.insert(Dbase).second;
        m_UserDBCount=m_UserDBs.size();
    }   // else

    return(ret_flag);

}   // DBListImpl::AddDB

void
DBListImpl::ReleaseDB(
    DBImpl * Dbase,
    bool IsInternal)
{
    db_set_t::iterator it;
    SpinLock lock(&m_Lock);

    if (IsInternal)
    {
        it=m_InternalDBs.find(Dbase);
        if (m_InternalDBs.end()!=it)
        {
            m_InternalDBs.erase(it);
        }   // if
        m_InternalDBCount=m_InternalDBs.size();
    }   // if
    else
    {
        it=m_UserDBs.find(Dbase);
        if (m_UserDBs.end()!=it)
        {
            m_UserDBs.erase(it);
        }   // if
        m_UserDBCount=m_UserDBs.size();
    }   // else

    return;

}   // DBListImpl::ReleaseDB

size_t
DBListImpl::GetDBCount(
    bool IsInternal)
{
    size_t ret_val;

    if (IsInternal)
        ret_val=m_InternalDBCount;
    else
        ret_val=m_UserDBCount;

    return(ret_val);

}   // DBListImpl::GetDBCount

void
DBListImpl::ScanDBs(
    bool IsInternal,
    void (DBImpl::* Function)())
{
    db_set_t::iterator it, first, last;
    SpinLock lock(&m_Lock);

    size_t count;

    // for_each() would have been fun, but setup deadlock
    //  scenarios
    // Now we have a race condition of us using the db object
    //  while someone is shutting it down ... hmm
    if (IsInternal)
    {
        first=m_InternalDBs.begin();
        last=m_InternalDBs.end();
        count=m_InternalDBs.size();
    }   // if
    else
    {
        first=m_UserDBs.begin();
        last=m_UserDBs.end();
        count=m_UserDBs.size();
    }   // else

#if 0  // for debugging ... sometimes
    m_Lock.Unlock(); /// might not be needed now
    syslog(LOG_ERR, "count %zd, total memory %" PRIu64 ", db cache size %" PRIu64 ", internal %d",
           count, gFlexCache.GetTotalMemory(), gFlexCache.GetDBCacheCapacity(IsInternal),
           (int)IsInternal);
    m_Lock.Lock();
#else
    count=count*2;  // kill off compiler warning
#endif

    // call member function of each database
    for (it=first; last!=it; ++it)
    {
        // must protect list from db add/delete during scan, leave locks
        ((*it)->*Function)();
    }   // for

    return;

}   // DBListImpl::ScanDBs

}  // namespace leveldb
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// socket_base.cpp
//
// Identification: src/wire/socket_base.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "wire/socket_base.h"
#include "wire/wire.h"
#include "common/exception.h"

#include <sys/un.h>
#include <string>

namespace peloton {
namespace wire {

template <typename B>
bool SocketManager<B>::RefillReadBuffer() {
  ssize_t bytes_read;

  // our buffer is to be emptied
  rbuf.Reset();

  // return explicitly
  for (;;) {
    //  try to fill the available space in the buffer
    bytes_read = read(sock_fd, &rbuf.buf[rbuf.buf_ptr],
                      SOCKET_BUFFER_SIZE - rbuf.buf_size);

    if (bytes_read < 0) {
		// Some other error occurred, close the socket, remove
		// the event and free the client structure.
      return false;
    }

    if (bytes_read == 0) {
	  // If the length of bytes returned by read is 0, this means
	  // that the client disconnected, remove the read event and the
	  // free the client structure.
      return false;
    }

    // read success, update buffer size
    rbuf.buf_size += bytes_read;

    // reset buffer ptr, to cover special case
    rbuf.buf_ptr = 0;
    return true;
  }
}

template <typename B>
bool SocketManager<B>::FlushWriteBuffer() {
  ssize_t written_bytes = 0;
  wbuf.buf_ptr = 0;
  // still outstanding bytes
  while (wbuf.buf_size - written_bytes > 0) {
    written_bytes = write(sock_fd, &wbuf.buf[wbuf.buf_ptr], wbuf.buf_size);
    if (written_bytes < 0) {
      switch(errno) {
      case EINTR:
    	  continue;
    	  break;
      case EAGAIN:
    	  LOG_INFO("Error Writing: EAGAIN");
    	  break;
      case EBADF:
    	  LOG_INFO("Error Writing: EBADF");
    	  break;
      case EDESTADDRREQ:
    	  LOG_INFO("Error Writing: EDESTADDRREQ");
    	  break;
      case EDQUOT:
    	  LOG_INFO("Error Writing: EDQUOT");
    	  break;
      case EFAULT:
    	  LOG_INFO("Error Writing: EFAULT");
    	  break;
      case EFBIG:
    	  LOG_INFO("Error Writing: EFBIG");
    	  break;
      case EINVAL:
    	  LOG_INFO("Error Writing: EINVAL");
    	  break;
      case EIO:
    	  LOG_INFO("Error Writing: EIO");
    	  break;
      case ENOSPC:
    	  LOG_INFO("Error Writing: ENOSPC");
    	  break;
      case EPIPE:
    	  LOG_INFO("Error Writing: EPIPE");
    	  break;
      default:
    	  LOG_INFO("Error Writing: UNKNOWN");
      }
      if (errno == EINTR) {
        // interrupts are ok, try again
        continue;
      } else {
        // fatal errors
        return false;
      }
    }

    // weird edge case?
    if (written_bytes == 0 && wbuf.buf_size != 0) {
    	LOG_INFO("Not all data is written");
      // fatal
      return false;
    }

    // update bookkeping
    wbuf.buf_ptr += written_bytes;
    wbuf.buf_size -= written_bytes;
  }

  // buffer is empty
  wbuf.Reset();

  // we are ok
  return true;
}

template <typename B>
bool SocketManager<B>::CanRead() {
  // Size of header (msg type + size)
  uint32_t header_size = sizeof(int32_t) + 1;
  uint32_t pkt_size = 0;
  // Size of available data for read
  size_t window = rbuf.buf_size - rbuf.buf_ptr;
  // If can read header
  if(header_size <= window) {
    PktBuf dummy_pkt;
	// Read the header size
	dummy_pkt.insert(std::end(dummy_pkt), std::begin(rbuf.buf) + rbuf.buf_ptr,
            std::begin(rbuf.buf) + rbuf.buf_ptr + header_size);
	// Get size of message
	std::copy(dummy_pkt.begin() + 1, dummy_pkt.end(),
	        reinterpret_cast<uchar *>(&pkt_size));
	pkt_size = ntohl(pkt_size) - sizeof(int32_t);
	// If header and size is larger than window, don't read untill receive a
	// read callback and buffer is refilled
	if(header_size + pkt_size > window) {
	  	return false;
	}
  }
  else {
	return false;
  }
  return true;
}

/*
 * read - Tries to read "bytes" bytes into packet's buffer. Returns true on
 * success.
 * 		false on failure. B can be any STL container.
 */
template <typename B>
bool SocketManager<B>::ReadBytes(B &pkt_buf, size_t bytes) {
  size_t window, pkt_buf_idx = 0;
  // while data still needs to be read
  while (bytes) {
    // how much data is available
    window = rbuf.buf_size - rbuf.buf_ptr;
    if (bytes <= window) {
      pkt_buf.insert(std::end(pkt_buf), std::begin(rbuf.buf) + rbuf.buf_ptr,
                     std::begin(rbuf.buf) + rbuf.buf_ptr + bytes);

      // move the pointer
      rbuf.buf_ptr += bytes;

      // move pkt_buf_idx as well
      pkt_buf_idx += bytes;

      return true;
    } else {
      // read what is available for non-trivial window
      if (window > 0) {
        pkt_buf.insert(std::end(pkt_buf), std::begin(rbuf.buf) + rbuf.buf_ptr,
                       std::begin(rbuf.buf) + rbuf.buf_size);

        // update bytes leftover
        bytes -= window;

        // update pkt_buf_idx
        pkt_buf_idx += window;
      }

      // refill buffer, reset buf ptr here
      if (!RefillReadBuffer()) {
        // nothing more to read, end
        return false;
      }
    }
  }

  return true;
}

template <typename B>
bool SocketManager<B>::BufferWriteBytes(B &pkt_buf, size_t len, uchar type) {
  size_t window, pkt_buf_ptr = 0;
  int len_nb;  // length in network byte order

  // check if we don't have enough space in the buffer
  if (wbuf.GetMaxSize() - wbuf.buf_ptr < 1 + sizeof(int32_t)) {
    // buffer needs to be flushed before adding header
    FlushWriteBuffer();
  }

  // assuming wbuf is now large enough to
  // fit type and size fields in one go
  if (type != 0) {
    // type shouldn't be ignored
    wbuf.buf[wbuf.buf_ptr++] = type;
  }

  // make len include its field size as well
  len_nb = htonl(len + sizeof(int32_t));

  // append the bytes of this integer in network-byte order
  std::copy(reinterpret_cast<uchar *>(&len_nb),
            reinterpret_cast<uchar *>(&len_nb) + 4,
            std::begin(wbuf.buf) + wbuf.buf_ptr);

  // move the write buffer pointer and update size of the socket buffer
  wbuf.buf_ptr += sizeof(int32_t);
  wbuf.buf_size = wbuf.buf_ptr;

  // fill the contents
  while (len) {
    window = wbuf.GetMaxSize() - wbuf.buf_ptr;
    if (len <= window) {
      // contents fit in the window, range copy "len" bytes
      std::copy(std::begin(pkt_buf) + pkt_buf_ptr,
                std::begin(pkt_buf) + pkt_buf_ptr + len,
                std::begin(wbuf.buf) + wbuf.buf_ptr);

      // Move the cursor and update size of socket buffer
      wbuf.buf_ptr += len;
      wbuf.buf_size = wbuf.buf_ptr;
      return true;
    } else {
      /* contents longer than socket buffer size, fill up the socket buffer
       *  with "window" bytes
       */
      std::copy(std::begin(pkt_buf) + pkt_buf_ptr,
                std::begin(pkt_buf) + pkt_buf_ptr + window,
                std::begin(wbuf.buf) + wbuf.buf_ptr);

      // move the packet's cursor
      pkt_buf_ptr += window;
      len -= window;

      wbuf.buf_size = wbuf.GetMaxSize();
      // write failure
      if (!FlushWriteBuffer()) return false;
    }
  }
  return true;
}

template <typename B>
void SocketManager<B>::CloseSocket() {
  for (;;) {
    int status = close(sock_fd);
    if (status < 0) {
      // failed close
      if (errno == EINTR) {
        // interrupted, try closing again
        continue;
      }
    }
    return;
  }
}

// explicit template instantiation for read_bytes
template class SocketManager<PktBuf>;

}  // End wire namespace
}  // End peloton namespace
<commit_msg>Use select to manage writes<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// socket_base.cpp
//
// Identification: src/wire/socket_base.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "wire/socket_base.h"
#include "wire/wire.h"
#include "common/exception.h"

#include <sys/un.h>
#include <string>

namespace peloton {
namespace wire {

template <typename B>
bool SocketManager<B>::RefillReadBuffer() {
  ssize_t bytes_read;

  // our buffer is to be emptied
  rbuf.Reset();

  // return explicitly
  for (;;) {
    //  try to fill the available space in the buffer
    bytes_read = read(sock_fd, &rbuf.buf[rbuf.buf_ptr],
                      SOCKET_BUFFER_SIZE - rbuf.buf_size);

    if (bytes_read < 0) {
		// Some other error occurred, close the socket, remove
		// the event and free the client structure.
      return false;
    }

    if (bytes_read == 0) {
	  // If the length of bytes returned by read is 0, this means
	  // that the client disconnected, remove the read event and the
	  // free the client structure.
      return false;
    }

    // read success, update buffer size
    rbuf.buf_size += bytes_read;

    // reset buffer ptr, to cover special case
    rbuf.buf_ptr = 0;
    return true;
  }
}

template <typename B>
bool SocketManager<B>::FlushWriteBuffer() {
  fd_set rset;
  struct timeval timeout;
  ssize_t written_bytes = 0;
  wbuf.buf_ptr = 0;
  // still outstanding bytes
  while ((int)wbuf.buf_size - written_bytes > 0) {
	  while(written_bytes <= 0){
			written_bytes = write(sock_fd, &wbuf.buf[wbuf.buf_ptr], wbuf.buf_size);
			if (written_bytes < 0) {
			  switch(errno) {
			  case EINTR:
				  continue;
				  break;
			  case EAGAIN:
				  LOG_INFO("Error Writing: EAGAIN");
				  break;
			  case EBADF:
				  LOG_INFO("Error Writing: EBADF");
				  break;
			  case EDESTADDRREQ:
				  LOG_INFO("Error Writing: EDESTADDRREQ");
				  break;
			  case EDQUOT:
				  LOG_INFO("Error Writing: EDQUOT");
				  break;
			  case EFAULT:
				  LOG_INFO("Error Writing: EFAULT");
				  break;
			  case EFBIG:
				  LOG_INFO("Error Writing: EFBIG");
				  break;
			  case EINVAL:
				  LOG_INFO("Error Writing: EINVAL");
				  break;
			  case EIO:
				  LOG_INFO("Error Writing: EIO");
				  break;
			  case ENOSPC:
				  LOG_INFO("Error Writing: ENOSPC");
				  break;
			  case EPIPE:
				  LOG_INFO("Error Writing: EPIPE");
				  break;
			  default:
				  LOG_INFO("Error Writing: UNKNOWN");
			  }
			  if (errno == EINTR) {
				// interrupts are ok, try again
				written_bytes = 0;
				continue;
			  } else if (errno == EAGAIN) {
				  FD_ZERO (&rset);
				  FD_SET (sock_fd, &rset);
				  timeout.tv_sec = 5;
				  written_bytes = select(sock_fd + 1, &rset, NULL, NULL, &timeout);
				  if (written_bytes < 0) {
					  LOG_INFO("written_bytes < 0 after select. Fatal");
					  exit(EXIT_FAILURE);
				  } else if (written_bytes == 0) {
					  // timed out without writing any data
					  LOG_INFO("Timeout without writing");
				  }
				  // else, socket is now readable, so loop back up and do the read() again
				  written_bytes = 0;
				  continue;
			  }
			  else {
				// fatal errors
				return false;
			  }
			}

			// weird edge case?
			if (written_bytes == 0 && wbuf.buf_size != 0) {
				LOG_INFO("Not all data is written");
			  // fatal
			  return false;
			}
	  }

    // update bookkeping
    wbuf.buf_ptr += written_bytes;
    wbuf.buf_size -= written_bytes;
  }

  // buffer is empty
  wbuf.Reset();

  // we are ok
  return true;
}

template <typename B>
bool SocketManager<B>::CanRead() {
  // Size of header (msg type + size)
  uint32_t header_size = sizeof(int32_t) + 1;
  uint32_t pkt_size = 0;
  // Size of available data for read
  size_t window = rbuf.buf_size - rbuf.buf_ptr;
  // If can read header
  if(header_size <= window) {
    PktBuf dummy_pkt;
	// Read the header size
	dummy_pkt.insert(std::end(dummy_pkt), std::begin(rbuf.buf) + rbuf.buf_ptr,
            std::begin(rbuf.buf) + rbuf.buf_ptr + header_size);
	// Get size of message
	std::copy(dummy_pkt.begin() + 1, dummy_pkt.end(),
	        reinterpret_cast<uchar *>(&pkt_size));
	pkt_size = ntohl(pkt_size) - sizeof(int32_t);
	// If header and size is larger than window, don't read untill receive a
	// read callback and buffer is refilled
	if(header_size + pkt_size > window) {
	  	return false;
	}
  }
  else {
	return false;
  }
  return true;
}

/*
 * read - Tries to read "bytes" bytes into packet's buffer. Returns true on
 * success.
 * 		false on failure. B can be any STL container.
 */
template <typename B>
bool SocketManager<B>::ReadBytes(B &pkt_buf, size_t bytes) {
  size_t window, pkt_buf_idx = 0;
  // while data still needs to be read
  while (bytes) {
    // how much data is available
    window = rbuf.buf_size - rbuf.buf_ptr;
    if (bytes <= window) {
      pkt_buf.insert(std::end(pkt_buf), std::begin(rbuf.buf) + rbuf.buf_ptr,
                     std::begin(rbuf.buf) + rbuf.buf_ptr + bytes);

      // move the pointer
      rbuf.buf_ptr += bytes;

      // move pkt_buf_idx as well
      pkt_buf_idx += bytes;

      return true;
    } else {
      // read what is available for non-trivial window
      if (window > 0) {
        pkt_buf.insert(std::end(pkt_buf), std::begin(rbuf.buf) + rbuf.buf_ptr,
                       std::begin(rbuf.buf) + rbuf.buf_size);

        // update bytes leftover
        bytes -= window;

        // update pkt_buf_idx
        pkt_buf_idx += window;
      }

      // refill buffer, reset buf ptr here
      if (!RefillReadBuffer()) {
        // nothing more to read, end
        return false;
      }
    }
  }

  return true;
}

template <typename B>
bool SocketManager<B>::BufferWriteBytes(B &pkt_buf, size_t len, uchar type) {
  size_t window, pkt_buf_ptr = 0;
  int len_nb;  // length in network byte order

  // check if we don't have enough space in the buffer
  if (wbuf.GetMaxSize() - wbuf.buf_ptr < 1 + sizeof(int32_t)) {
    // buffer needs to be flushed before adding header
    FlushWriteBuffer();
  }

  // assuming wbuf is now large enough to
  // fit type and size fields in one go
  if (type != 0) {
    // type shouldn't be ignored
    wbuf.buf[wbuf.buf_ptr++] = type;
  }

  // make len include its field size as well
  len_nb = htonl(len + sizeof(int32_t));

  // append the bytes of this integer in network-byte order
  std::copy(reinterpret_cast<uchar *>(&len_nb),
            reinterpret_cast<uchar *>(&len_nb) + 4,
            std::begin(wbuf.buf) + wbuf.buf_ptr);

  // move the write buffer pointer and update size of the socket buffer
  wbuf.buf_ptr += sizeof(int32_t);
  wbuf.buf_size = wbuf.buf_ptr;

  // fill the contents
  while (len) {
    window = wbuf.GetMaxSize() - wbuf.buf_ptr;
    if (len <= window) {
      // contents fit in the window, range copy "len" bytes
      std::copy(std::begin(pkt_buf) + pkt_buf_ptr,
                std::begin(pkt_buf) + pkt_buf_ptr + len,
                std::begin(wbuf.buf) + wbuf.buf_ptr);

      // Move the cursor and update size of socket buffer
      wbuf.buf_ptr += len;
      wbuf.buf_size = wbuf.buf_ptr;
      return true;
    } else {
      /* contents longer than socket buffer size, fill up the socket buffer
       *  with "window" bytes
       */
      std::copy(std::begin(pkt_buf) + pkt_buf_ptr,
                std::begin(pkt_buf) + pkt_buf_ptr + window,
                std::begin(wbuf.buf) + wbuf.buf_ptr);

      // move the packet's cursor
      pkt_buf_ptr += window;
      len -= window;

      wbuf.buf_size = wbuf.GetMaxSize();
      // write failure
      if (!FlushWriteBuffer()) return false;
    }
  }
  return true;
}

template <typename B>
void SocketManager<B>::CloseSocket() {
  for (;;) {
    int status = close(sock_fd);
    if (status < 0) {
      // failed close
      if (errno == EINTR) {
        // interrupted, try closing again
        continue;
      }
    }
    return;
  }
}

// explicit template instantiation for read_bytes
template class SocketManager<PktBuf>;

}  // End wire namespace
}  // End peloton namespace
<|endoftext|>