<commit_before>//https://code.google.com/p/nya-engine/

#include "text_parser.h"
#include "log/log.h"
#include "memory/invalid_object.h"

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstring>

namespace
{
    const char global_marker='@';
    const char *whitespaces=" \t\r\n";
    const char *special_chars="=:";
}

namespace nya_formats
{

const char *text_parser::get_section_type(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].type.c_str();
}

int text_parser::get_section_names_count(int idx) const
{
    if(idx < 0 || idx >= (int)m_sections.size())
        return 0;

    return (int)m_sections[idx].names.size();
}

const char *text_parser::get_section_name(int idx,int name_idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    if(name_idx<0 || name_idx>=(int)m_sections[idx].names.size())
        return 0;

    return m_sections[idx].names[name_idx].c_str();
}

const char *text_parser::get_section_option(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].option.c_str();
}

const char *text_parser::get_section_value(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].value.c_str();
}

nya_math::vec4 text_parser::get_section_value_vector(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return nya_memory::get_invalid_object<nya_math::vec4>();

    nya_math::vec4 v;
    std::string s=m_sections[idx].value;
    std::replace(s.begin(),s.end(),',',' ');
    std::istringstream iss(s);
    if(iss>>v.x)
        if(iss>>v.y)
            if(iss>>v.z)
                iss>>v.w;
    return v;
}

int text_parser::get_subsections_count(int section_idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size())
        return -1;

    const section &s=m_sections[section_idx];
    if(!s.subsection_parsed)
    {
        // parse subsection
        line l=line::first(s.value.c_str(),s.value.size());
        while(l.next())
        {
            std::list<std::string> tokens=tokenize_line(l);
            if(tokens.size()>0)
            {
                s.subsections.push_back(subsection());
                subsection &ss=s.subsections.back();
                std::list<std::string>::iterator iter=tokens.begin();
                ss.type = *(iter++);
                if(iter!=tokens.end() && *(iter++) == "=")
                {
                    if(iter!=tokens.end())
                        ss.value=*iter;
                }
            }
        }

        s.subsection_parsed=true;
    }

    return (int)s.subsections.size();
}

const char *text_parser::get_subsection_type(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    return m_sections[section_idx].subsections[idx].type.c_str();
}

const char *text_parser::get_subsection_value(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    return m_sections[section_idx].subsections[idx].value.c_str();
}

bool text_parser::get_subsection_value_bool(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    std::string s=m_sections[section_idx].subsections[idx].value;
    std::transform(s.begin(),s.end(),s.begin(),::tolower);
    return s=="yes" || s=="1" || s=="true";
}

text_parser::line text_parser::line::first(const char *text,size_t text_size)
{
    line l;
    l.text=text;
    l.text_size=text_size;
    l.offset=l.size=0;
    l.global=l.empty=false;
    l.line_number=l.next_line_number=1;
    return l;
}

// line knows about quotes, '\n' characters inside quotes are not treated as new line
bool text_parser::line::next()
{
    if(offset+size>=text_size)
        return false;

    offset+=size;
    line_number=next_line_number;

    // calculate line size, keep in mind multiline quoted tokens
    size_t char_idx=offset;
    bool in_quotes=false;
    while(char_idx!=text_size)
    {
        char c=text[char_idx++];
        if(c=='\n')
        {
            ++next_line_number;
            if(!in_quotes)
                break;
        }
        else if(c=='"')
            in_quotes=!in_quotes;
    }

    size=char_idx-offset;

    const size_t first_non_whitespace_idx=skip_whitespaces(text,text_size,offset);
    global=(first_non_whitespace_idx<offset+size && text[first_non_whitespace_idx]==global_marker);
    empty=(first_non_whitespace_idx>=offset+size);

    return true;
}

bool text_parser::load_from_data(const char *text,size_t text_size)
{
    if(!text)
        return false;

    text_size=get_real_text_size(text,text_size);
    if(!text_size)
        return false;

    size_t global_count=0;
    line l=line::first(text,text_size);
    while(l.next()) if(l.global) ++global_count;
    m_sections.resize(global_count);

    size_t subsection_start_idx=0,subsection_end_idx=0,sections_count=0;
    bool subsection_empty=true;
    l=line::first(text,text_size);

    while(l.next())
    {
        if(l.global)
        {
            if(subsection_end_idx>subsection_start_idx && !subsection_empty)
            {
                m_sections[sections_count-1].value=std::string(text+subsection_start_idx,subsection_end_idx-subsection_start_idx);
                subsection_empty=true;
            }
            fill_section(m_sections[sections_count],l);
            subsection_start_idx=l.offset+l.size;
            ++sections_count;
        }
        else
        {
            if(sections_count>0)
            {
                subsection_end_idx=l.offset+l.size;
                if(!l.empty)
                    subsection_empty=false;
            }
            else if(!l.empty)
            {
                nya_log::log()<<"Text parser: subsection found before any section declaration at lines "<< l.line_number<<"-"<<l.next_line_number<<"\n";
            }
        }
    }

    if(subsection_end_idx>subsection_start_idx && !subsection_empty)
        m_sections[sections_count-1].value=std::string(text+subsection_start_idx,subsection_end_idx-subsection_start_idx);

    return true;
}

void text_parser::fill_section(section &s,const line &l)
{
   std::list<std::string> tokens=tokenize_line(l);
    // assert(tokens.size() > 0);
    // assert(tokens.front().size > 0);
    // assert(tokens.front().at(0) == global_marker);
    std::list<std::string>::iterator iter=tokens.begin();
    s.type.swap(*(iter++));
    bool need_option=false;
    bool need_value=false;
    bool need_name=true;
    while(iter!=tokens.end())
    {
        if(need_option)
        {
            s.option.swap(*iter);
            need_option=false;
        }
        else if(need_value)
        {
            s.value.swap(*iter);
            need_value=false;
        }
        else if(*iter==":")
        {
            need_option=true;
            need_name=false;
        }
        else if(*iter=="=")
        {
            need_value=true;
            need_name=false;
        }
        else if(need_name)
        {
            if(s.names.empty() || !s.names.back().empty())
                s.names.push_back(std::string());

            s.names.back().swap(*iter);
        }
        else
        {
            nya_log::log()<<"Text parser: unexpected token at lines "<<l.line_number<<"-"<<l.next_line_number<<"\n";
            break;
        }

        ++iter;
    }
}

std::list<std::string> text_parser::tokenize_line(const line &l)
{
    std::list<std::string> result;
    const size_t line_end=l.offset+l.size;
    size_t char_idx=l.offset;

    while(true)
    {
        size_t token_start_idx, token_size;
        char_idx=get_next_token(l.text,line_end,char_idx,token_start_idx,token_size);
        if(token_start_idx<line_end)
            result.push_back(std::string(l.text+token_start_idx,token_size));
        else
            break;
    }

    return result;
}

size_t text_parser::get_real_text_size(const char *text,size_t supposed_size)
{
    const char *t=text;
    if(supposed_size!=no_size)
        while(*t && t<text+supposed_size) ++t;
    else
        while(*t) ++t;

    return t-text;
}

size_t text_parser::get_next_token(const char *text,size_t text_size,size_t pos,size_t &token_start_idx_out,size_t &token_size_out)
{
    size_t char_idx=pos;
    char_idx=skip_whitespaces(text,text_size,char_idx);
    if(char_idx<text_size && strchr(special_chars,text[char_idx]))
    {
        token_start_idx_out=char_idx;
        token_size_out=1;
        return char_idx+1;
    }

    if(char_idx>=text_size)
    {
        token_start_idx_out=text_size;
        token_size_out=0;
        return text_size;
    }

    token_start_idx_out=char_idx;
    bool quoted_token=false;
    if(text[char_idx]=='"')
    {
        ++char_idx;
        token_start_idx_out=char_idx;
        quoted_token=true;
    }

    size_t token_end_idx=token_start_idx_out;
    bool end_found=false;
    while(char_idx<text_size && !end_found)
    {
        char c=text[char_idx];
        if(quoted_token)
        {
            if(c=='"')
            {
                token_end_idx=char_idx;
                end_found=true;
            }

            ++char_idx;
        }
        else
        {
            if(strchr(whitespaces,c) || strchr(special_chars, c))
            {
                token_end_idx=char_idx;
                end_found=true;
            }
            else
                ++char_idx;
        }
    }

    token_size_out=(end_found?token_end_idx:text_size)-token_start_idx_out;

    return char_idx;
}

size_t text_parser::skip_whitespaces(const char *text,size_t text_size,size_t pos)
{
    while(pos<text_size && strchr(whitespaces,text[pos]))
        ++pos;

    return pos;
}

void text_parser::debug_print(nya_log::ostream_base &os) const
{
    for(size_t i=0;i<m_sections.size();++i)
    {
        const section &s=m_sections[i];
        os<<"section "<<i<<" '"<<s.type<<"':\n";
        for(size_t j=0;j<s.names.size();++j)
            os<<"  name "<<j<<" '"<<s.names[j]<<"'\n";

        if(!s.option.empty())
            os<<"  option '"<<s.option<<"'\n";
        os<<"  value '"<<s.value<<"'\n\n\n";
    }
}

}
<commit_msg>formats / text parser comments<commit_after>//https://code.google.com/p/nya-engine/

#include "text_parser.h"
#include "log/log.h"
#include "memory/invalid_object.h"

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstring>

namespace
{
    const char global_marker='@';
    const char *whitespaces=" \t\r\n";
    const char *special_chars="=:";
}

namespace nya_formats
{

const char *text_parser::get_section_type(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].type.c_str();
}

int text_parser::get_section_names_count(int idx) const
{
    if(idx < 0 || idx >= (int)m_sections.size())
        return 0;

    return (int)m_sections[idx].names.size();
}

const char *text_parser::get_section_name(int idx,int name_idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    if(name_idx<0 || name_idx>=(int)m_sections[idx].names.size())
        return 0;

    return m_sections[idx].names[name_idx].c_str();
}

const char *text_parser::get_section_option(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].option.c_str();
}

const char *text_parser::get_section_value(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return 0;

    return m_sections[idx].value.c_str();
}

nya_math::vec4 text_parser::get_section_value_vector(int idx) const
{
    if(idx<0 || idx>=(int)m_sections.size())
        return nya_memory::get_invalid_object<nya_math::vec4>();

    nya_math::vec4 v;
    std::string s=m_sections[idx].value;
    std::replace(s.begin(),s.end(),',',' ');
    std::istringstream iss(s);
    if(iss>>v.x)
        if(iss>>v.y)
            if(iss>>v.z)
                iss>>v.w;
    return v;
}

int text_parser::get_subsections_count(int section_idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size())
        return -1;

    const section &s=m_sections[section_idx];
    if(!s.subsection_parsed)
    {
        // parse subsection
        line l=line::first(s.value.c_str(),s.value.size());
        while(l.next())
        {
            std::list<std::string> tokens=tokenize_line(l);
            if(tokens.size()>0)
            {
                s.subsections.push_back(subsection());
                subsection &ss=s.subsections.back();
                std::list<std::string>::iterator iter=tokens.begin();
                ss.type = *(iter++);
                if(iter!=tokens.end() && *(iter++) == "=")
                {
                    if(iter!=tokens.end())
                        ss.value=*iter;
                }
            }
        }

        s.subsection_parsed=true;
    }

    return (int)s.subsections.size();
}

const char *text_parser::get_subsection_type(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    return m_sections[section_idx].subsections[idx].type.c_str();
}

const char *text_parser::get_subsection_value(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    return m_sections[section_idx].subsections[idx].value.c_str();
}

bool text_parser::get_subsection_value_bool(int section_idx,int idx) const
{
    if(section_idx<0 || section_idx>=(int)m_sections.size() ||
       idx<0 || idx>=(int)m_sections[section_idx].subsections.size())
        return 0;

    std::string s=m_sections[section_idx].subsections[idx].value;
    std::transform(s.begin(),s.end(),s.begin(),::tolower);
    return s=="yes" || s=="1" || s=="true";
}

text_parser::line text_parser::line::first(const char *text,size_t text_size)
{
    line l;
    l.text=text;
    l.text_size=text_size;
    l.offset=l.size=0;
    l.global=l.empty=false;
    l.line_number=l.next_line_number=1;
    return l;
}

// line knows about quotes, '\n' characters inside quotes are not treated as new line
bool text_parser::line::next()
{
    if(offset+size>=text_size)
        return false;

    offset+=size;
    line_number=next_line_number;

    // calculate line size, keep in mind multiline quoted tokens
    size_t char_idx=offset;
    bool in_quotes=false;
    while(char_idx!=text_size)
    {
        char c=text[char_idx++];
        if(c=='\n')
        {
            ++next_line_number;
            if(!in_quotes)
                break;
        }
        else if(c=='"')
            in_quotes=!in_quotes;
    }

    size=char_idx-offset;

    const size_t first_non_whitespace_idx=skip_whitespaces(text,text_size,offset);
    global=(first_non_whitespace_idx<offset+size && text[first_non_whitespace_idx]==global_marker);
    empty=(first_non_whitespace_idx>=offset+size);

    return true;
}

bool text_parser::load_from_data(const char *text,size_t text_size)
{
    if(!text)
        return false;

    text_size=get_real_text_size(text,text_size);
    if(!text_size)
        return false;

    //removing comments
    std::string uncommented_text(text,text_size);
    while(uncommented_text.find("//")!=std::string::npos)
    {
        const size_t from=uncommented_text.find("//");
        uncommented_text.erase(from,uncommented_text.find_first_of("\n\r",from+1)-from);
    }
    while(uncommented_text.find("/*")!=std::string::npos)
    {
        const size_t from=uncommented_text.find("/*");
        uncommented_text.erase(from,(uncommented_text.find("*/",from+2)-from)+2);
    }
    text=uncommented_text.c_str();
    text_size=uncommented_text.size();

    size_t global_count=0;
    line l=line::first(text,text_size);
    while(l.next()) if(l.global) ++global_count;
    m_sections.resize(global_count);

    size_t subsection_start_idx=0,subsection_end_idx=0,sections_count=0;
    bool subsection_empty=true;
    l=line::first(text,text_size);

    while(l.next())
    {
        if(l.global)
        {
            if(subsection_end_idx>subsection_start_idx && !subsection_empty)
            {
                m_sections[sections_count-1].value=std::string(text+subsection_start_idx,subsection_end_idx-subsection_start_idx);
                subsection_empty=true;
            }
            fill_section(m_sections[sections_count],l);
            subsection_start_idx=l.offset+l.size;
            ++sections_count;
        }
        else
        {
            if(sections_count>0)
            {
                subsection_end_idx=l.offset+l.size;
                if(!l.empty)
                    subsection_empty=false;
            }
            else if(!l.empty)
            {
                nya_log::log()<<"Text parser: subsection found before any section declaration at lines "<< l.line_number<<"-"<<l.next_line_number<<"\n";
            }
        }
    }

    if(subsection_end_idx>subsection_start_idx && !subsection_empty)
        m_sections[sections_count-1].value=std::string(text+subsection_start_idx,subsection_end_idx-subsection_start_idx);

    return true;
}

void text_parser::fill_section(section &s,const line &l)
{
   std::list<std::string> tokens=tokenize_line(l);
    // assert(tokens.size() > 0);
    // assert(tokens.front().size > 0);
    // assert(tokens.front().at(0) == global_marker);
    std::list<std::string>::iterator iter=tokens.begin();
    s.type.swap(*(iter++));
    bool need_option=false;
    bool need_value=false;
    bool need_name=true;
    while(iter!=tokens.end())
    {
        if(need_option)
        {
            s.option.swap(*iter);
            need_option=false;
        }
        else if(need_value)
        {
            s.value.swap(*iter);
            need_value=false;
        }
        else if(*iter==":")
        {
            need_option=true;
            need_name=false;
        }
        else if(*iter=="=")
        {
            need_value=true;
            need_name=false;
        }
        else if(need_name)
        {
            if(s.names.empty() || !s.names.back().empty())
                s.names.push_back(std::string());

            s.names.back().swap(*iter);
        }
        else
        {
            nya_log::log()<<"Text parser: unexpected token at lines "<<l.line_number<<"-"<<l.next_line_number<<"\n";
            break;
        }

        ++iter;
    }
}

std::list<std::string> text_parser::tokenize_line(const line &l)
{
    std::list<std::string> result;
    const size_t line_end=l.offset+l.size;
    size_t char_idx=l.offset;

    while(true)
    {
        size_t token_start_idx, token_size;
        char_idx=get_next_token(l.text,line_end,char_idx,token_start_idx,token_size);
        if(token_start_idx<line_end)
            result.push_back(std::string(l.text+token_start_idx,token_size));
        else
            break;
    }

    return result;
}

size_t text_parser::get_real_text_size(const char *text,size_t supposed_size)
{
    const char *t=text;
    if(supposed_size!=no_size)
        while(*t && t<text+supposed_size) ++t;
    else
        while(*t) ++t;

    return t-text;
}

size_t text_parser::get_next_token(const char *text,size_t text_size,size_t pos,size_t &token_start_idx_out,size_t &token_size_out)
{
    size_t char_idx=pos;
    char_idx=skip_whitespaces(text,text_size,char_idx);
    if(char_idx<text_size && strchr(special_chars,text[char_idx]))
    {
        token_start_idx_out=char_idx;
        token_size_out=1;
        return char_idx+1;
    }

    if(char_idx>=text_size)
    {
        token_start_idx_out=text_size;
        token_size_out=0;
        return text_size;
    }

    token_start_idx_out=char_idx;
    bool quoted_token=false;
    if(text[char_idx]=='"')
    {
        ++char_idx;
        token_start_idx_out=char_idx;
        quoted_token=true;
    }

    size_t token_end_idx=token_start_idx_out;
    bool end_found=false;
    while(char_idx<text_size && !end_found)
    {
        char c=text[char_idx];
        if(quoted_token)
        {
            if(c=='"')
            {
                token_end_idx=char_idx;
                end_found=true;
            }

            ++char_idx;
        }
        else
        {
            if(strchr(whitespaces,c) || strchr(special_chars, c))
            {
                token_end_idx=char_idx;
                end_found=true;
            }
            else
                ++char_idx;
        }
    }

    token_size_out=(end_found?token_end_idx:text_size)-token_start_idx_out;

    return char_idx;
}

size_t text_parser::skip_whitespaces(const char *text,size_t text_size,size_t pos)
{
    while(pos<text_size && strchr(whitespaces,text[pos]))
        ++pos;

    return pos;
}

void text_parser::debug_print(nya_log::ostream_base &os) const
{
    for(size_t i=0;i<m_sections.size();++i)
    {
        const section &s=m_sections[i];
        os<<"section "<<i<<" '"<<s.type<<"':\n";
        for(size_t j=0;j<s.names.size();++j)
            os<<"  name "<<j<<" '"<<s.names[j]<<"'\n";

        if(!s.option.empty())
            os<<"  option '"<<s.option<<"'\n";
        os<<"  value '"<<s.value<<"'\n\n\n";
    }
}

}
<|endoftext|>


<commit_before>#ifndef AX_LINEAR_ALGEBRA_H
#define AX_LINEAR_ALGEBRA_H
#include "MatrixVectorMultiplication.hpp"

namespace ax
{
    using Realvec = RealVector<3>;
    using Matrix3 = RealMatrix<3,3>;
    using Matrix4 = RealMatrix<4,4>;
}

#include "JacobiMethod.hpp"

#endif //AX_LINEAR_ALGEBRA_H
<commit_msg>add rotation into LA & change default name<commit_after>#ifndef AX_LINEAR_ALGEBRA_H
#define AX_LINEAR_ALGEBRA_H
#include "MatrixVectorMultiplication.hpp"

// reuquire Boost.math
#include "VectorRotation.hpp"

namespace ax
{
    using Vector3d = RealVector<3>;
    using Matrix3  = RealMatrix<3,3>;
    using Matrix4  = RealMatrix<4,4>;
}

#include "JacobiMethod.hpp"

#endif //AX_LINEAR_ALGEBRA_H
<|endoftext|>


<commit_before>#include <stdlib.h>

#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/atomic.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/shared_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
//this quiets a deprecated warning
#define BOOST_NO_HASH
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>

#include <iostream>
#include <deque>

boost::atomic<unsigned> nsimultaneous, noutstanding;

namespace asio = boost::asio;
asio::io_service io_service;
boost::thread_group tgroup;

struct data {
  float value;
  typedef boost::shared_ptr<data> ptr;
  typedef boost::shared_ptr<const data> const_ptr;
};

typedef std::deque<data::const_ptr> datadeque;

struct module : boost::enable_shared_from_this<module> , boost::noncopyable
{
  typedef boost::shared_ptr<module> ptr;
  typedef std::map<std::string, datadeque> inputs_t;
  inputs_t inputs;

  typedef std::map<std::string, std::pair<ptr, std::string> > outputs_t;
  outputs_t outputs;

  boost::mutex mtx;

  bool inputs_ready()
  {
    boost::unique_lock<boost::mutex> lock(mtx);
    if (inputs.size() == 0)
      {
        std::cout << this << " READY CAUSE NO INPUTS\n";
        return true;
      }
    for (inputs_t::iterator it = inputs.begin(), end = inputs.end();
         it != end;
         ++it)
      {
        if (it->second.size() == 0)
          return false;
      }
    return true;
  }

  void push(const std::string& port, data::const_ptr newdata)
  {
    boost::unique_lock<boost::mutex> lock(mtx);
    inputs[port].push_back(newdata);
  }

  void doit(boost::asio::io_service& serv)
  {
    data::ptr newdata(new data);
    newdata->value = 1;
    {
      boost::unique_lock<boost::mutex> lock(mtx);
      for (inputs_t::iterator it = inputs.begin(), end = inputs.end();
           it != end;
           ++it)
        {
          newdata->value += it->second.front()->value;
          it->second.pop_front();
        }
    }
    std::cout << this << " new value = " << newdata->value << "\n";
    std::cout << this << " pushing to " << outputs.size() << " outputs" << std::endl;
    // spend some time working
    unsigned ms_work = rand() % 3000;
    boost::asio::io_service inner_serv;
    boost::asio::deadline_timer dt(inner_serv);
    dt.expires_from_now(boost::posix_time::milliseconds(ms_work));
    dt.wait();

    for (outputs_t::iterator it = outputs.begin(), end = outputs.end();
         it != end;
         ++it)
      {
        module::ptr downstream_module = it->second.first;
        const std::string& downstream_port = it->second.second;

        std::cout << this << " => " << downstream_port << "\n";
        downstream_module->push(downstream_port, newdata);
      }

    run(serv);
  }

  static void
  async_waitforinput(boost::asio::io_service& serv,
                     module::ptr m)
  {
    std::cout << m.get() << " waiting..." << std::endl;
    boost::asio::io_service inner_serv;
    boost::asio::deadline_timer dt(inner_serv);
    boost::asio::io_service::work work(serv);

    assert(m.get());

    for (;;) {
      if (m->inputs_ready())
        {
          serv.post(boost::bind(&module::doit, m.get(), boost::ref(serv)));
          std::cout << m.get() << " inputs ready! " << m->inputs.size() << std::endl;
          return;
        }
      dt.expires_from_now(boost::posix_time::milliseconds(3));
      dt.wait();
    }
  }

  boost::scoped_ptr<boost::thread> input_watcher;

  void run(boost::asio::io_service& serv)
  {
    if (input_watcher)
      input_watcher->join();
    input_watcher.reset(new boost::thread(boost::bind(&async_waitforinput,
                                                      boost::ref(serv),
                                                      shared_from_this())));
  }
};

module::ptr
make_graph(boost::asio::io_service& serv, unsigned N)
{
  module::ptr root(new module);
  root->run(serv);
  module::ptr prev = root;
  module::ptr next;

  for (unsigned n=0; n<N; ++n)
    {
      next.reset(new module);
      next->inputs["in"];
      prev->outputs["out"] = make_pair(next, std::string("in"));
      next->run(serv);
      prev = next;
    }
  return root;
}

using boost::vertex_property_tag;
using boost::adjacency_list;
using boost::vecS;
using boost::setS;
using boost::bidirectionalS;
using boost::property;
using boost::property_map;
using boost::graph_traits;

struct edge
{
  std::string from_port, to_port;
  std::deque<boost::any> deque;
  typedef boost::shared_ptr<edge> ptr;
  typedef boost::shared_ptr<const edge> const_ptr;
};

typedef adjacency_list<vecS, // OutEdgeList
                       vecS, // VertexList
                       bidirectionalS, // Directed
                       module::ptr, // vertex property
                       edge::ptr> // edge property
graph_t;

int main()
{
  using boost::bind;
  namespace asio = boost::asio;

  std::cout << "start..." << std::endl;

  graph_t g;

  module::ptr m1(new module), m2(new module);
  edge::ptr e1(new edge), e2(new edge);

  graph_t::vertex_descriptor vd1 = add_vertex(m1, g),
    vd2 = add_vertex(m2, g);

  bool added;
  graph_t::edge_descriptor ed1, ed2;
  tie(ed1, added) = add_edge(vd1, vd2, e1, g);
  assert(added);
  tie(ed2, added) = add_edge(vd1, vd2, e2, g);
  assert(added);

  std::ofstream gviz_str("graph.dot");
  boost::write_graphviz(gviz_str, g);

  /*

  module::ptr graph = make_graph(io_service, 30);

  graph->run(io_service);

  {
    for (unsigned j=0; j<1; ++j)
      {
        tgroup.create_thread(bind(&asio::io_service::run, &io_service));
      }
  }

  tgroup.join_all();
  */
  std::cout << "exit." << std::endl;
}
<commit_msg>happy graph printing<commit_after>#include <stdlib.h>

#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/atomic.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/shared_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
//this quiets a deprecated warning
#define BOOST_NO_HASH
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/foreach.hpp>

#include <iostream>
#include <deque>

boost::atomic<unsigned> nsimultaneous, noutstanding;

namespace asio = boost::asio;
asio::io_service io_service;
boost::thread_group tgroup;

struct data {
  float value;
  typedef boost::shared_ptr<data> ptr;
  typedef boost::shared_ptr<const data> const_ptr;
};

typedef std::deque<data::const_ptr> datadeque;

struct module : boost::enable_shared_from_this<module> , boost::noncopyable
{
  typedef boost::shared_ptr<module> ptr;
  typedef std::map<std::string, datadeque> inputs_t;
  inputs_t inputs;

  typedef std::map<std::string, std::pair<ptr, std::string> > outputs_t;
  outputs_t outputs;

  boost::mutex mtx;

  std::string name;

  module(const std::string& name_) : name(name_) { }

  bool inputs_ready()
  {
    boost::unique_lock<boost::mutex> lock(mtx);
    if (inputs.size() == 0)
      {
        std::cout << this << " READY CAUSE NO INPUTS\n";
        return true;
      }
    for (inputs_t::iterator it = inputs.begin(), end = inputs.end();
         it != end;
         ++it)
      {
        if (it->second.size() == 0)
          return false;
      }
    return true;
  }

  void push(const std::string& port, data::const_ptr newdata)
  {
    boost::unique_lock<boost::mutex> lock(mtx);
    inputs[port].push_back(newdata);
  }

  void doit(boost::asio::io_service& serv)
  {
    data::ptr newdata(new data);
    newdata->value = 1;
    {
      boost::unique_lock<boost::mutex> lock(mtx);
      for (inputs_t::iterator it = inputs.begin(), end = inputs.end();
           it != end;
           ++it)
        {
          newdata->value += it->second.front()->value;
          it->second.pop_front();
        }
    }
    std::cout << this << " new value = " << newdata->value << "\n";
    std::cout << this << " pushing to " << outputs.size() << " outputs" << std::endl;
    // spend some time working
    unsigned ms_work = rand() % 3000;
    boost::asio::io_service inner_serv;
    boost::asio::deadline_timer dt(inner_serv);
    dt.expires_from_now(boost::posix_time::milliseconds(ms_work));
    dt.wait();

    for (outputs_t::iterator it = outputs.begin(), end = outputs.end();
         it != end;
         ++it)
      {
        module::ptr downstream_module = it->second.first;
        const std::string& downstream_port = it->second.second;

        std::cout << this << " => " << downstream_port << "\n";
        downstream_module->push(downstream_port, newdata);
      }

    run(serv);
  }

  static void
  async_waitforinput(boost::asio::io_service& serv,
                     module::ptr m)
  {
    std::cout << m.get() << " waiting..." << std::endl;
    boost::asio::io_service inner_serv;
    boost::asio::deadline_timer dt(inner_serv);
    boost::asio::io_service::work work(serv);

    assert(m.get());

    for (;;) {
      if (m->inputs_ready())
        {
          serv.post(boost::bind(&module::doit, m.get(), boost::ref(serv)));
          std::cout << m.get() << " inputs ready! " << m->inputs.size() << std::endl;
          return;
        }
      dt.expires_from_now(boost::posix_time::milliseconds(3));
      dt.wait();
    }
  }

  boost::scoped_ptr<boost::thread> input_watcher;

  void run(boost::asio::io_service& serv)
  {
    if (input_watcher)
      input_watcher->join();
    input_watcher.reset(new boost::thread(boost::bind(&async_waitforinput,
                                                      boost::ref(serv),
                                                      shared_from_this())));
  }
};

using boost::adjacency_list;
using boost::vecS;
using boost::bidirectionalS;
using boost::graph_traits;

struct edge
{
  edge(const std::string& fp, const std::string& tp)
    : from_port(fp), to_port(tp)
  { }

  std::string from_port, to_port;
  std::deque<boost::any> deque;
  typedef boost::shared_ptr<edge> ptr;
  typedef boost::shared_ptr<const edge> const_ptr;
};

// if the first argument is a sequence type (vecS, etc) then parallel edges are allowed
typedef adjacency_list<vecS, // OutEdgeList...
                       vecS, // VertexList
                       bidirectionalS, // Directed
                       module::ptr, // vertex property
                       edge::ptr> // edge property
graph_t;

struct vertex_writer
{
  graph_t* g;
  vertex_writer(graph_t* g_) : g(g_) { }

  void operator()(std::ostream& out, graph_t::vertex_descriptor vd)
  {
    out << "[label=\"" << (*g)[vd]->name << "\"]";
  }
};

struct edge_writer
{
  graph_t* g;
  edge_writer(graph_t* g_) : g(g_) { }

  void operator()(std::ostream& out, graph_t::edge_descriptor ed)
  {
    out << "[headlabel=\"" << (*g)[ed]->to_port << "\" taillabel=\"" << (*g)[ed]->from_port << "\"]";
  }
};

struct graph_writer
{
  void operator()(std::ostream& out) const {
    out << "graph [rankdir=LR, ranksep=1]" << std::endl;
    out << "edge [labelfontsize=8]" << std::endl;
  }
};

int main()
{
  using boost::bind;
  namespace asio = boost::asio;

  std::cout << "start..." << std::endl;

  graph_t g;

  module::ptr m1(new module("m1")), m2(new module("m2"));
  edge::ptr e1(new edge("out1", "in1")), e2(new edge("out2", "in2"));

  graph_t::vertex_descriptor vd1 = add_vertex(m1, g),
    vd2 = add_vertex(m2, g);

  bool added;
  graph_t::edge_descriptor ed1, ed2;
  tie(ed1, added) = add_edge(vd1, vd2, e1, g);
  assert(added);
  tie(ed2, added) = add_edge(vd1, vd2, e2, g);
  assert(added);

  std::ofstream gviz_str("graph.dot");
  boost::write_graphviz(gviz_str, g, vertex_writer(&g), edge_writer(&g), graph_writer());

  /*
  module::ptr graph = make_graph(io_service, 30);

  graph->run(io_service);

  {
    for (unsigned j=0; j<1; ++j)
      {
        tgroup.create_thread(bind(&asio::io_service::run, &io_service));
      }
  }

  tgroup.join_all();
  */
  std::cout << "exit." << std::endl;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
//
// Under windows, when multiple versions of maya are installed,
// maya2egg can accidentally use the wrong version of OpenMaya.dll.
// This small wrapper program alters your PATH and MAYA_LOCATION
// environment variables in order to ensure that maya2egg finds the
// right DLLs.
//
// To use this wrapper, maya2egg.exe must be renamed to
// maya2egg-wrapped.exe.  Then, this wrapper program must be
// installed as maya2egg.exe
//
///////////////////////////////////////////////////////////////////////

#ifndef MAYAVERSION
#error You must define the symbol MAYAVERSION when compiling mayawrapper.
#endif

#define QUOTESTR(x) #x
#define TOSTRING(x) QUOTESTR(x)

#define _CRT_SECURE_NO_DEPRECATE 1

#ifdef _WIN32
  #include <windows.h>
  #include <winuser.h>
  #include <process.h>
#else
  #include <string.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <unistd.h>
  #define _putenv putenv
#endif
#ifdef __APPLE__
  #include <sys/malloc.h>
#else
  #include <malloc.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#define PATH_MAX 1024

#ifdef __APPLE__
  // This is for _NSGetExecutablePath().
  #include <mach-o/dyld.h>
#endif

#if defined(_WIN32)
struct { char *ver, *key; } reg_keys[] = {
  { "MAYA6",    "6.0" },
  { "MAYA65",   "6.5" },
  { "MAYA7",    "7.0" },
  { "MAYA8",    "8.0" },
  { "MAYA85",   "8.5" },
  { "MAYA2008", "2008" },
  { "MAYA2009", "2009" },
  { 0, 0 },
};

char *getRegistryKey(char *ver) {
  for (int i=0; reg_keys[i].ver != 0; i++) {
    if (strcmp(reg_keys[i].ver, ver)==0) {
      return reg_keys[i].key;
    }
  }
  return 0;
}

void getMayaLocation(char *ver, char *loc)
{
  char fullkey[1024], *developer;
  HKEY hkey; DWORD size, dtype; LONG res; int dev, hive;

  for (dev=0; dev<3; dev++) {
    switch (dev) {
    case 0: developer="Alias|Wavefront"; break;
    case 1: developer="Alias"; break;
    case 2: developer="Autodesk"; break;
    }
    sprintf(fullkey, "SOFTWARE\\%s\\Maya\\%s\\Setup\\InstallPath", developer, ver);
    for (hive=0; hive<2; hive++) {
      loc[0] = 0;
      res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | (hive ? 256:0), &hkey);
      if (res == ERROR_SUCCESS) {
        size=1024;
        res = RegQueryValueEx(hkey, "MAYA_INSTALL_LOCATION", NULL, &dtype, (LPBYTE)loc, &size);
        if ((res == ERROR_SUCCESS)&&(dtype == REG_SZ)) {
          loc[size] = 0;
          return;
        } else {
          loc[0] = 0;
        }
        RegCloseKey(hkey);
      }
    }
  }
}

void getWrapperName(char *prog)
{
  DWORD res;
  res = GetModuleFileName(NULL, prog, 1000);
  if (res == 0) {
    prog[0] = 0;
    return;
  }
  int len = strlen(prog);
  if (_stricmp(prog+len-4, ".exe")) {
    prog[0] = 0;
    return;
  }
  prog[len-4] = 0;
}
#elif defined(__APPLE__)
void getWrapperName(char *prog)
{
  char *pathbuf = new char[PATH_MAX];
  uint32_t *bufsize;
  if (_NSGetExecutablePath(pathbuf, bufsize) == 0) {
    strcpy(prog, pathbuf);
  }
  delete[] pathbuf;
}
#else
void getWrapperName(char *prog)
{
  char readlinkbuf[PATH_MAX];
  int pathlen = readlink("/proc/self/exe", readlinkbuf, PATH_MAX-1);
  if (pathlen > 0) {
    readlinkbuf[pathlen] = 0;
    strcpy(prog, readlinkbuf);
  }
}
#endif

int main(int argc, char **argv)
{
  char loc[1024], prog[1024];
  char *path, *env1, *env2, *env3, *env4; int len;

#ifdef _WIN32
  STARTUPINFO si; PROCESS_INFORMATION pi;
  char *key, *cmd;

  key = getRegistryKey(TOSTRING(MAYAVERSION));
  if (key == 0) {
    printf("MayaWrapper: unknown maya version %s\n", TOSTRING(MAYAVERSION));
    exit(1);
  }
  getMayaLocation(key, loc);
  if (loc[0]==0) {
    printf("Cannot locate %s - it does not appear to be installed\n", TOSTRING(MAYAVERSION));
    exit(1);
  }

  getWrapperName(prog);
  if (prog[0]==0) {
    printf("mayaWrapper cannot determine its own filename (bug)\n");
    exit(1);
  }
  strcat(prog, "-wrapped.exe");
#else
  if (getenv("MAYA_LOCATION") == NULL) {
    printf("$MAYA_LOCATION is not set!\n");
    exit(1);
  } else {
    strcpy(loc, getenv("MAYA_LOCATION"));
  }

  struct stat st;
  if(stat(loc, &st) != 0) {
    printf("The directory referred to by $MAYA_LOCATION does not exist!\n");
    exit(1);
  }

  getWrapperName(prog);
  if (prog[0]==0) {
    printf("mayaWrapper cannot determine its own filename (bug)\n");
    exit(1);
  }
  strcat(prog, "-wrapped");
#endif

  path = getenv("PATH");
  if (path == 0) path = "";
#ifdef _WIN32
  env1 = (char*)malloc(100 + strlen(loc) + strlen(path));
  sprintf(env1, "PATH=%s\\bin;%s", loc, path);
  env2 = (char*)malloc(100 + strlen(loc));
  sprintf(env2, "MAYA_LOCATION=%s", loc);
  env3 = (char*)malloc(300 + 5*strlen(loc));
  sprintf(env3, "PYTHONPATH=%s\\bin;%s\\Python;%s\\Python\\DLLs;%s\\Python\\lib;%s\\Python\\lib\\site-packages", loc, loc, loc, loc, loc);
#else
  env1 = (char*)malloc(100 + strlen(loc) + strlen(path));
  sprintf(env1, "PATH=%s/bin:%s", loc, path);
  env2 = (char*)malloc(100 + strlen(loc));
  sprintf(env2, "MAYA_LOCATION=%s", loc);
  env3 = (char*)malloc(100 + strlen(loc));
  sprintf(env3, "PYTHONHOME=%s", loc);
  env4 = (char*)malloc(100 + strlen(loc));
  sprintf(env4, "LD_LIBRARY_PATH=%s/lib", loc);

  _putenv(env3);
  _putenv(env4);
#endif
  _putenv(env1);
  _putenv(env2);
  //  _putenv(env3);

#ifdef _WIN32
  cmd = GetCommandLine();
  memset(&si, 0, sizeof(si));
  si.cb = sizeof(STARTUPINFO);
  if (CreateProcess(prog, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
    WaitForSingleObject(pi.hProcess, INFINITE);
    exit(0);
  } else {
    printf("Could not launch %s\n", prog);
    exit(1);
  }
#else
  if (execvp(prog, argv) == 0) {
    exit(0);
  } else {
    printf("Could not launch %s\n", prog);
    exit(1);
  }
#endif
}

<commit_msg>Better support for non-windows platforms<commit_after>///////////////////////////////////////////////////////////////////////
//
// When multiple versions of maya are installed, maya2egg can
// accidentally use the wrong version of the OpenMaya libraries.
// This small wrapper program alters your PATH, MAYA_LOCATION, etc
// environment variables in order to ensure that maya2egg finds the
// right ligraries.
//
// To use this wrapper, maya2egg must be renamed to maya2egg-wrapped.
// Then, this wrapper program must be installed as maya2egg.
//
///////////////////////////////////////////////////////////////////////

#ifndef MAYAVERSION
#error You must define the symbol MAYAVERSION when compiling mayawrapper.
#endif

#define QUOTESTR(x) #x
#define TOSTRING(x) QUOTESTR(x)

#define _CRT_SECURE_NO_DEPRECATE 1

#ifdef _WIN32
  #include <windows.h>
  #include <winuser.h>
  #include <process.h>
#else
  #include <string.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <unistd.h>
  #define _putenv putenv
#endif
#ifdef __APPLE__
  #include <sys/malloc.h>
#else
  #include <malloc.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#define PATH_MAX 1024

#ifdef __APPLE__
  // This is for _NSGetExecutablePath().
  #include <mach-o/dyld.h>
#endif

struct { char *ver, *key; } maya_versions[] = {
  { "MAYA6",    "6.0" },
  { "MAYA65",   "6.5" },
  { "MAYA7",    "7.0" },
  { "MAYA8",    "8.0" },
  { "MAYA85",   "8.5" },
  { "MAYA2008", "2008" },
  { "MAYA2009", "2009" },
  { 0, 0 },
};

char *getVersionNumber(char *ver) {
  for (int i=0; maya_versions[i].ver != 0; i++) {
    if (strcmp(maya_versions[i].ver, ver)==0) {
      return maya_versions[i].key;
    }
  }
  return 0;
}

#if defined(_WIN32)
void getMayaLocation(char *ver, char *loc)
{
  char fullkey[1024], *developer;
  HKEY hkey; DWORD size, dtype; LONG res; int dev, hive;

  for (dev=0; dev<3; dev++) {
    switch (dev) {
    case 0: developer="Alias|Wavefront"; break;
    case 1: developer="Alias"; break;
    case 2: developer="Autodesk"; break;
    }
    sprintf(fullkey, "SOFTWARE\\%s\\Maya\\%s\\Setup\\InstallPath", developer, ver);
    for (hive=0; hive<2; hive++) {
      loc[0] = 0;
      res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | (hive ? 256:0), &hkey);
      if (res == ERROR_SUCCESS) {
        size=1024;
        res = RegQueryValueEx(hkey, "MAYA_INSTALL_LOCATION", NULL, &dtype, (LPBYTE)loc, &size);
        if ((res == ERROR_SUCCESS)&&(dtype == REG_SZ)) {
          loc[size] = 0;
          return;
        } else {
          loc[0] = 0;
        }
        RegCloseKey(hkey);
      }
    }
  }
}

void getWrapperName(char *prog)
{
  DWORD res;
  res = GetModuleFileName(NULL, prog, 1000);
  if (res == 0) {
    prog[0] = 0;
    return;
  }
  int len = strlen(prog);
  if (_stricmp(prog+len-4, ".exe")) {
    prog[0] = 0;
    return;
  }
  prog[len-4] = 0;
}

#elif defined(__APPLE__)
void getMayaLocation(char *ver, char *loc)
{
  char mpath[64];
  sprintf(mpath, "/Applications/Autodesk/maya%s/Maya.app/Contents", ver);
  struct stat st;
  if(stat(mpath, &st) == 0) {
    strcpy(loc, mpath);
  } else {
    loc[0] = 0;
  }
}

void getWrapperName(char *prog)
{
  char *pathbuf = new char[PATH_MAX];
  uint32_t bufsize = PATH_MAX;
  if (_NSGetExecutablePath(pathbuf, &bufsize) == 0) {
    strcpy(prog, pathbuf);
  } else {
    prog[0] = 0;
  }
  delete[] pathbuf;
}

#else
void getMayaLocation(char *ver, char *loc)
{
  char mpath[64];
  sprintf(mpath, "/usr/autodesk/maya%s", ver);
  struct stat st;
  if(stat(mpath, &st) == 0) {
    strcpy(loc, mpath);
  } else {
    sprintf(mpath, "/usr/aw/maya%s", ver);
    if(stat(mpath, &st) == 0) {
      strcpy(loc, mpath);
    } else {
      loc[0] = 0;
    }
  }
}

void getWrapperName(char *prog)
{
  char readlinkbuf[PATH_MAX];
  int pathlen = readlink("/proc/self/exe", readlinkbuf, PATH_MAX-1);
  if (pathlen > 0) {
    readlinkbuf[pathlen] = 0;
    strcpy(prog, readlinkbuf);
  } else {
    prog[0] = 0;
  }
}
#endif

int main(int argc, char **argv)
{
  char loc[1024], prog[1024];
  char *key, *path, *env1, *env2, *env3, *env4; int len;

  key = getVersionNumber(TOSTRING(MAYAVERSION));
  if (key == 0) {
    printf("MayaWrapper: unknown maya version %s\n", TOSTRING(MAYAVERSION));
    exit(1);
  }

  getMayaLocation(key, loc);
  if (loc[0]==0) {
    printf("Cannot locate %s - it does not appear to be installed\n", TOSTRING(MAYAVERSION));
    exit(1);
  }

  getWrapperName(prog);
  if (prog[0]==0) {
    printf("mayaWrapper cannot determine its own filename (bug)\n");
    exit(1);
  }

#ifdef _WIN32
  strcat(prog, "-wrapped.exe");
#else
  strcat(prog, "-wrapped");
#endif

#ifdef _WIN32
  path = getenv("PATH");
  if (path == 0) path = "";
  env1 = (char*)malloc(100 + strlen(loc) + strlen(path));
  sprintf(env1, "PATH=%s\\bin;%s", loc, path);
  env2 = (char*)malloc(100 + strlen(loc));
  sprintf(env2, "MAYA_LOCATION=%s", loc);
  env3 = (char*)malloc(300 + 5*strlen(loc));
  sprintf(env3, "PYTHONPATH=%s\\bin;%s\\Python;%s\\Python\\DLLs;%s\\Python\\lib;%s\\Python\\lib\\site-packages", loc, loc, loc, loc, loc);
#else
#ifdef __APPLE__
  path = getenv("DYLD_LIBRARY_PATH");
  if (path == 0) path = "";
  env1 = (char*)malloc(100 + strlen(loc) + strlen(path));
  sprintf(env1, "DYLD_LIBRARY_PATH=%s/MacOS:%s", loc, path);
#else
  path = getenv("LD_LIBRARY_PATH");
  if (path == 0) path = "";
  env1 = (char*)malloc(100 + strlen(loc) + strlen(path));
  sprintf(env1, "LD_LIBRARY_PATH=%s/lib:%s", loc, path);
#endif // __APPLE__
  env2 = (char*)malloc(100 + strlen(loc));
  sprintf(env2, "MAYA_LOCATION=%s", loc);
  env3 = (char*)malloc(100 + strlen(loc));
  sprintf(env3, "PYTHONHOME=%s/Frameworks/Python.framework/Versions/Current", loc);

  _putenv(env3);
#endif // _WIN32
  _putenv(env1);
  _putenv(env2);
  //  _putenv(env3);

#ifdef _WIN32
  STARTUPINFO si; PROCESS_INFORMATION pi;
  char *cmd;

  cmd = GetCommandLine();
  memset(&si, 0, sizeof(si));
  si.cb = sizeof(STARTUPINFO);
  if (CreateProcess(prog, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
    WaitForSingleObject(pi.hProcess, INFINITE);
    exit(0);
  } else {
    printf("Could not launch %s\n", prog);
    exit(1);
  }
#else
  if (execvp(prog, argv) == 0) {
    exit(0);
  } else {
    printf("Could not launch %s\n", prog);
    exit(1);
  }
#endif
}

<|endoftext|>


<commit_before>#include "greedy_solver.h"

#include <algorithm>
#include <functional>
#include <vector>

#include "cyc_limits.h"
#include "logger.h"

namespace cyclus {

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::~GreedySolver() {
  if (conditioner_ != NULL)
    delete conditioner_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::Solve() {
  if (conditioner_ != NULL) {
    conditioner_->Condition(graph_);
  }

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::GreedilySatisfySet_),
                    this));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::GreedilySatisfySet_(RequestGroup::Ptr prs) {
  double target = prs->qty();
  double match = 0;
  const std::vector<ExchangeNode::Ptr>& nodes = prs->nodes();
  std::vector<ExchangeNode::Ptr>::const_iterator req_it = nodes.begin();
  std::vector<Arc>::const_iterator arc_it;

  CLOG(LEV_DEBUG1) << "Greedy Solving for " << target
                   << " amount of a resource.";
  while( (match <= target) && (req_it != nodes.end()) ) {
    // this if statement is needed because map.at() will throw if the key does
    // not exist, which is a corner case for when there is a request with no bid
    // arcs associated with it
    if (graph_->node_arc_map().count(*req_it) > 0) {
      const std::vector<Arc>& arcs = graph_->node_arc_map().at(*req_it);
      std::vector<Arc> sorted(arcs); // make a copy for now
      std::sort(sorted.begin(), sorted.end(), ReqPrefComp);
      arc_it = sorted.begin();

      while( (match <= target) && (arc_it != sorted.end()) ) {
        double remain = target - match;
        double tomatch = std::min(remain, Capacity(*arc_it));

        if (arc_it->exclusive) {
          // this implementation is for requester-specific exclusivity
          double excl_val = arc_it->excl_val;
          tomatch = (tomatch < excl_val) ? 0 : tomatch;
        }

        if (tomatch > eps()) {
          CLOG(LEV_DEBUG1) << "Greedy Solver is matching " << tomatch
                           << " amount of a resource.";
          graph_->AddMatch(*arc_it, tomatch);
          match += tomatch;
        }
        ++arc_it;
      } // while( (match =< target) && (arc_it != arcs.end()) )
    } // if(graph_->node_arc_map().count(*req_it) > 0)

    ++req_it;
  } // while( (match =< target) && (req_it != nodes.end()) )

}

} // namespace cyclus
<commit_msg>made greedy algorithm a little simpler for exclusive arcs<commit_after>#include "greedy_solver.h"

#include <algorithm>
#include <functional>
#include <vector>

#include "cyc_limits.h"
#include "logger.h"

namespace cyclus {

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::~GreedySolver() {
  if (conditioner_ != NULL)
    delete conditioner_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::Solve() {
  if (conditioner_ != NULL) {
    conditioner_->Condition(graph_);
  }

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::GreedilySatisfySet_),
                    this));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::GreedilySatisfySet_(RequestGroup::Ptr prs) {
  double target = prs->qty();
  double match = 0;
  const std::vector<ExchangeNode::Ptr>& nodes = prs->nodes();
  std::vector<ExchangeNode::Ptr>::const_iterator req_it = nodes.begin();
  std::vector<Arc>::const_iterator arc_it;

  CLOG(LEV_DEBUG1) << "Greedy Solving for " << target
                   << " amount of a resource.";
  while( (match <= target) && (req_it != nodes.end()) ) {
    // this if statement is needed because map.at() will throw if the key does
    // not exist, which is a corner case for when there is a request with no bid
    // arcs associated with it
    if (graph_->node_arc_map().count(*req_it) > 0) {
      const std::vector<Arc>& arcs = graph_->node_arc_map().at(*req_it);
      std::vector<Arc> sorted(arcs); // make a copy for now
      std::sort(sorted.begin(), sorted.end(), ReqPrefComp);
      arc_it = sorted.begin();

      while( (match <= target) && (arc_it != sorted.end()) ) {
        double remain = target - match;
        double tomatch = std::min(remain, Capacity(*arc_it));

        // this implementat-ion is for requester-specific exclusivity
        tomatch = (arc_it->exclusive && tomatch < arc_it->excl_val) ?
                  0 : tomatch;

        if (tomatch > eps()) {
          CLOG(LEV_DEBUG1) << "Greedy Solver is matching " << tomatch
                           << " amount of a resource.";
          graph_->AddMatch(*arc_it, tomatch);
          match += tomatch;
        }
        ++arc_it;
      } // while( (match =< target) && (arc_it != arcs.end()) )
    } // if(graph_->node_arc_map().count(*req_it) > 0)

    ++req_it;
  } // while( (match =< target) && (req_it != nodes.end()) )

}

} // namespace cyclus
<|endoftext|>


<commit_before>#include <string.h>
#include <assert.h>
#include <boost/lexical_cast.hpp>
#include "Dmac_Channel.h"
#include "DMAC.h"
#include "RegisterStateFile.h"
#include "Log.h"

#define LOG_NAME				("dmac")
#define STATE_PREFIX			("dmac/channel_")
#define STATE_SUFFIX			(".xml")
#define STATE_REGS_CHCR			("CHCR")
#define STATE_REGS_MADR			("MADR")
#define STATE_REGS_QWC			("QWC")
#define STATE_REGS_TADR			("TADR")
#define STATE_REGS_SCCTRL		("SCCTRL")
#define STATE_REGS_ASR0			("ASR0")
#define STATE_REGS_ASR1			("ASR1")

using namespace Dmac;

CChannel::CChannel(CDMAC& dmac, unsigned int nNumber, const DmaReceiveHandler& pReceive)
: m_dmac(dmac)
, m_nNumber(nNumber)
, m_pReceive(pReceive)
{

}

CChannel::~CChannel()
{

}

void CChannel::Reset()
{
	memset(&m_CHCR, 0, sizeof(CHCR));
	m_nMADR		= 0;
	m_nQWC		= 0;
	m_nTADR		= 0;
	m_nSCCTRL	= 0;
	m_nASR[0]	= 0;
	m_nASR[1]	= 0;
}

void CChannel::SaveState(Framework::CZipArchiveWriter& archive)
{
	std::string path = STATE_PREFIX + boost::lexical_cast<std::string>(m_nNumber) + STATE_SUFFIX;
	CRegisterStateFile* registerFile = new CRegisterStateFile(path.c_str());
	registerFile->SetRegister32(STATE_REGS_CHCR,	m_CHCR);
	registerFile->SetRegister32(STATE_REGS_MADR,	m_nMADR);
	registerFile->SetRegister32(STATE_REGS_QWC,		m_nQWC);
	registerFile->SetRegister32(STATE_REGS_TADR,	m_nTADR);
	registerFile->SetRegister32(STATE_REGS_SCCTRL,	m_nSCCTRL);
	registerFile->SetRegister32(STATE_REGS_ASR0,	m_nASR[0]);
	registerFile->SetRegister32(STATE_REGS_ASR1,	m_nASR[1]);
	archive.InsertFile(registerFile);
}

void CChannel::LoadState(Framework::CZipArchiveReader& archive)
{
	std::string path = STATE_PREFIX + boost::lexical_cast<std::string>(m_nNumber) + STATE_SUFFIX;
	CRegisterStateFile registerFile(*archive.BeginReadFile(path.c_str()));
	m_CHCR		<<= registerFile.GetRegister32(STATE_REGS_CHCR);
	m_nMADR		= registerFile.GetRegister32(STATE_REGS_MADR);
	m_nQWC		= registerFile.GetRegister32(STATE_REGS_QWC);
	m_nTADR		= registerFile.GetRegister32(STATE_REGS_TADR);
	m_nSCCTRL	= registerFile.GetRegister32(STATE_REGS_SCCTRL);
	m_nASR[0]	= registerFile.GetRegister32(STATE_REGS_ASR0);
	m_nASR[1]	= registerFile.GetRegister32(STATE_REGS_ASR1);
}

uint32 CChannel::ReadCHCR()
{
	return *(uint32*)&m_CHCR;
}

void CChannel::WriteCHCR(uint32 nValue)
{
	bool nSuspend = false;

	//We need to check if the purpose of this write is to suspend the current transfer
	if(m_dmac.m_D_ENABLE & CDMAC::ENABLE_CPND)
	{
		nSuspend = (m_CHCR.nSTR != 0) && ((nValue & CDMAC::CHCR_STR) == 0);
	}

	if(m_CHCR.nSTR == 1)
	{
		m_CHCR.nSTR = ~m_CHCR.nSTR;
		m_CHCR.nSTR = ((nValue & CDMAC::CHCR_STR) != 0) ? 1 : 0;
	}
	else
	{
		m_CHCR = *(CHCR*)&nValue;
	}

	if(m_CHCR.nSTR != 0)
	{
		if(m_nQWC == 0)
		{
			m_nSCCTRL |= SCCTRL_INITXFER;
		}
		m_nSCCTRL &= ~SCCTRL_RETTOP;
		Execute();
	}
}

void CChannel::Execute()
{
	if(m_CHCR.nSTR != 0)
	{
		if(m_dmac.m_D_ENABLE)
		{
			if(m_nNumber != 4)
			{
				throw std::runtime_error("Need to check that case.");
			}
			return;
		}
		if((m_nNumber == 1) && (m_CHCR.nDIR == 0))
		{
			//Humm, destination mode, not supported for now.
			CLog::GetInstance().Print(LOG_NAME, "Warning: Using destination mode for channel %d. Cancelling transfer.\r\n", m_nNumber);
			m_CHCR.nSTR = 0;
			return;
		}
		switch(m_CHCR.nMOD)
		{
		case 0x00:
			ExecuteNormal();
			break;
		case 0x01:
			ExecuteSourceChain();
			break;
		default:
			assert(0);
			break;
		}
	}
}

void CChannel::ExecuteNormal()
{
	uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

	m_nMADR	+= nRecv * 0x10;
	m_nQWC	-= nRecv;

	if(m_nQWC == 0)
	{
		ClearSTR();
	}
}

void CChannel::ExecuteSourceChain()
{
	//Execute current
	if(m_nQWC != 0)
	{
		uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

		m_nMADR	+= nRecv * 0x10;
		m_nQWC	-= nRecv;

		if(m_nQWC != 0)
		{
			//Transfer isn't finished, suspend for now
			return;
		}
	}

	while(m_CHCR.nSTR == 1)
	{
		//Check if MFIFO is enabled with this channel
		if(m_dmac.m_D_CTRL.mfd == 0x02 && m_nNumber == 1)
		{
			//Hold transfer if not ready
			if(m_nTADR == m_dmac.m_D8.m_nMADR)
			{
				break;
			}

//			uint32 currentPos = (m_nTADR & m_dmac.m_D_RBSR) + m_dmac.m_D_RBOR;
//			if(currentPos != m_nTADR)
//			{
//				int i = 0;
//				i++;
//			}
		}

		//Check if device received DMAtag
		if(m_CHCR.nReserved0)
		{
			assert(m_CHCR.nTTE);
			m_CHCR.nReserved0 = 0;
			if(m_pReceive(m_nTADR, 1, 0, true) != 1)
			{
				//Device didn't receive DmaTag, break for now
				m_CHCR.nReserved0 = 1;
				break;
			}
		}
		else
		{
			//Check if we've finished our DMA transfer
			if(m_nQWC == 0)
			{
				if(m_nSCCTRL & SCCTRL_INITXFER)
				{
					//Clear this bit
					m_nSCCTRL &= ~SCCTRL_INITXFER;
				}
				else
				{
					if(CDMAC::IsEndTagId((uint32)m_CHCR.nTAG << 16))
					{
						ClearSTR();
						continue;
					}

					//Transfer must also end when we encounter a RET tag with ASR == 0
					if(m_nSCCTRL & SCCTRL_RETTOP)
					{
						ClearSTR();
						m_nSCCTRL &= ~SCCTRL_RETTOP;
						continue;
					}
				}
			}
			else
			{
				//Suspend transfer
				break;
			}

			if(m_CHCR.nTTE == 1)
			{
				m_CHCR.nReserved0 = 0;
				if(m_pReceive(m_nTADR, 1, 0, true) != 1)
				{
					//Device didn't receive DmaTag, break for now
					m_CHCR.nReserved0 = 1;
					break;
				}
			}
		}

		//Half-Life does this...
		if(m_nTADR == 0)
		{
			ClearSTR();
			continue;
		}

		uint64 nTag = m_dmac.FetchDMATag(m_nTADR);

		//Save higher 16 bits of tag into CHCR
		m_CHCR.nTAG = nTag >> 16;
		//m_nCHCR &= ~0xFFFF0000;
		//m_nCHCR |= nTag & 0xFFFF0000;

		uint8 nID = (uint8)((nTag >> 28) & 0x07);

		switch(nID)
		{
		case 0:
			//REFE - Data to transfer is pointer in memory address, transfer is done
			m_nMADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= m_nTADR + 0x10;
			break;
		case 1:
			//CNT - Data to transfer is after the tag, next tag is after the data
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)(nTag & 0xFFFF);
			m_nTADR		= (m_nQWC * 0x10) + m_nMADR;
			break;
		case 2:
			//NEXT - Transfers data after tag, next tag is at position in ADDR field
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			break;
		case 3:
		case 4:
			//REF/REFS - Data to transfer is pointed in memory address, next tag is after this tag
			m_nMADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= m_nTADR + 0x10;
			break;
		case 5:
			//CALL - Transfers QWC after the tag, saves next address in ASR, TADR = ADDR
			assert(m_CHCR.nASP < 2);
			m_nMADR				= m_nTADR + 0x10;
			m_nQWC				= (uint32)(nTag & 0xFFFF);
			m_nASR[m_CHCR.nASP]	= m_nMADR + (m_nQWC * 0x10);
			m_nTADR				= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_CHCR.nASP++;
			break;
		case 6:
			//RET - Transfers QWC after the tag, pops TADR from ASR
			m_nMADR = m_nTADR + 0x10;
			m_nQWC = (uint32)(nTag & 0xFFFF);
			if(m_CHCR.nASP > 0)
			{
				m_CHCR.nASP--;
				m_nTADR = m_nASR[m_CHCR.nASP];
			}
			else
			{
				m_nSCCTRL |= SCCTRL_RETTOP;
			}
			break;
		case 7:
			//END - Data to transfer is after the tag, transfer is finished
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)(nTag & 0xFFFF);
			break;
		default:
			m_nQWC = 0;
			assert(0);
			break;
		}

		if(m_nQWC != 0)
		{
			uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

			m_nMADR		+= nRecv * 0x10;
			m_nQWC		-= nRecv;
		}
	}
}

void CChannel::SetReceiveHandler(const DmaReceiveHandler& handler)
{
	m_pReceive = handler;
}

void CChannel::ClearSTR()
{
	m_CHCR.nSTR = ~m_CHCR.nSTR;

	//Set interrupt
	m_dmac.m_D_STAT |= (1 << m_nNumber);

	m_dmac.UpdateCpCond();
}
<commit_msg>Removed dead code.<commit_after>#include <string.h>
#include <assert.h>
#include <boost/lexical_cast.hpp>
#include "Dmac_Channel.h"
#include "DMAC.h"
#include "RegisterStateFile.h"
#include "Log.h"

#define LOG_NAME				("dmac")
#define STATE_PREFIX			("dmac/channel_")
#define STATE_SUFFIX			(".xml")
#define STATE_REGS_CHCR			("CHCR")
#define STATE_REGS_MADR			("MADR")
#define STATE_REGS_QWC			("QWC")
#define STATE_REGS_TADR			("TADR")
#define STATE_REGS_SCCTRL		("SCCTRL")
#define STATE_REGS_ASR0			("ASR0")
#define STATE_REGS_ASR1			("ASR1")

using namespace Dmac;

CChannel::CChannel(CDMAC& dmac, unsigned int nNumber, const DmaReceiveHandler& pReceive)
: m_dmac(dmac)
, m_nNumber(nNumber)
, m_pReceive(pReceive)
{

}

CChannel::~CChannel()
{

}

void CChannel::Reset()
{
	memset(&m_CHCR, 0, sizeof(CHCR));
	m_nMADR		= 0;
	m_nQWC		= 0;
	m_nTADR		= 0;
	m_nSCCTRL	= 0;
	m_nASR[0]	= 0;
	m_nASR[1]	= 0;
}

void CChannel::SaveState(Framework::CZipArchiveWriter& archive)
{
	std::string path = STATE_PREFIX + boost::lexical_cast<std::string>(m_nNumber) + STATE_SUFFIX;
	CRegisterStateFile* registerFile = new CRegisterStateFile(path.c_str());
	registerFile->SetRegister32(STATE_REGS_CHCR,	m_CHCR);
	registerFile->SetRegister32(STATE_REGS_MADR,	m_nMADR);
	registerFile->SetRegister32(STATE_REGS_QWC,		m_nQWC);
	registerFile->SetRegister32(STATE_REGS_TADR,	m_nTADR);
	registerFile->SetRegister32(STATE_REGS_SCCTRL,	m_nSCCTRL);
	registerFile->SetRegister32(STATE_REGS_ASR0,	m_nASR[0]);
	registerFile->SetRegister32(STATE_REGS_ASR1,	m_nASR[1]);
	archive.InsertFile(registerFile);
}

void CChannel::LoadState(Framework::CZipArchiveReader& archive)
{
	std::string path = STATE_PREFIX + boost::lexical_cast<std::string>(m_nNumber) + STATE_SUFFIX;
	CRegisterStateFile registerFile(*archive.BeginReadFile(path.c_str()));
	m_CHCR		<<= registerFile.GetRegister32(STATE_REGS_CHCR);
	m_nMADR		= registerFile.GetRegister32(STATE_REGS_MADR);
	m_nQWC		= registerFile.GetRegister32(STATE_REGS_QWC);
	m_nTADR		= registerFile.GetRegister32(STATE_REGS_TADR);
	m_nSCCTRL	= registerFile.GetRegister32(STATE_REGS_SCCTRL);
	m_nASR[0]	= registerFile.GetRegister32(STATE_REGS_ASR0);
	m_nASR[1]	= registerFile.GetRegister32(STATE_REGS_ASR1);
}

uint32 CChannel::ReadCHCR()
{
	return *(uint32*)&m_CHCR;
}

void CChannel::WriteCHCR(uint32 nValue)
{
	bool nSuspend = false;

	//We need to check if the purpose of this write is to suspend the current transfer
	if(m_dmac.m_D_ENABLE & CDMAC::ENABLE_CPND)
	{
		nSuspend = (m_CHCR.nSTR != 0) && ((nValue & CDMAC::CHCR_STR) == 0);
	}

	if(m_CHCR.nSTR == 1)
	{
		m_CHCR.nSTR = ((nValue & CDMAC::CHCR_STR) != 0) ? 1 : 0;
	}
	else
	{
		m_CHCR = *(CHCR*)&nValue;
	}

	if(m_CHCR.nSTR != 0)
	{
		if(m_nQWC == 0)
		{
			m_nSCCTRL |= SCCTRL_INITXFER;
		}
		m_nSCCTRL &= ~SCCTRL_RETTOP;
		Execute();
	}
}

void CChannel::Execute()
{
	if(m_CHCR.nSTR != 0)
	{
		if(m_dmac.m_D_ENABLE)
		{
			if(m_nNumber != 4)
			{
				throw std::runtime_error("Need to check that case.");
			}
			return;
		}
		if((m_nNumber == 1) && (m_CHCR.nDIR == 0))
		{
			//Humm, destination mode, not supported for now.
			CLog::GetInstance().Print(LOG_NAME, "Warning: Using destination mode for channel %d. Cancelling transfer.\r\n", m_nNumber);
			m_CHCR.nSTR = 0;
			return;
		}
		switch(m_CHCR.nMOD)
		{
		case 0x00:
			ExecuteNormal();
			break;
		case 0x01:
			ExecuteSourceChain();
			break;
		default:
			assert(0);
			break;
		}
	}
}

void CChannel::ExecuteNormal()
{
	uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

	m_nMADR	+= nRecv * 0x10;
	m_nQWC	-= nRecv;

	if(m_nQWC == 0)
	{
		ClearSTR();
	}
}

void CChannel::ExecuteSourceChain()
{
	//Execute current
	if(m_nQWC != 0)
	{
		uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

		m_nMADR	+= nRecv * 0x10;
		m_nQWC	-= nRecv;

		if(m_nQWC != 0)
		{
			//Transfer isn't finished, suspend for now
			return;
		}
	}

	while(m_CHCR.nSTR == 1)
	{
		//Check if MFIFO is enabled with this channel
		if(m_dmac.m_D_CTRL.mfd == 0x02 && m_nNumber == 1)
		{
			//Hold transfer if not ready
			if(m_nTADR == m_dmac.m_D8.m_nMADR)
			{
				break;
			}

//			uint32 currentPos = (m_nTADR & m_dmac.m_D_RBSR) + m_dmac.m_D_RBOR;
//			if(currentPos != m_nTADR)
//			{
//				int i = 0;
//				i++;
//			}
		}

		//Check if device received DMAtag
		if(m_CHCR.nReserved0)
		{
			assert(m_CHCR.nTTE);
			m_CHCR.nReserved0 = 0;
			if(m_pReceive(m_nTADR, 1, 0, true) != 1)
			{
				//Device didn't receive DmaTag, break for now
				m_CHCR.nReserved0 = 1;
				break;
			}
		}
		else
		{
			//Check if we've finished our DMA transfer
			if(m_nQWC == 0)
			{
				if(m_nSCCTRL & SCCTRL_INITXFER)
				{
					//Clear this bit
					m_nSCCTRL &= ~SCCTRL_INITXFER;
				}
				else
				{
					if(CDMAC::IsEndTagId((uint32)m_CHCR.nTAG << 16))
					{
						ClearSTR();
						continue;
					}

					//Transfer must also end when we encounter a RET tag with ASR == 0
					if(m_nSCCTRL & SCCTRL_RETTOP)
					{
						ClearSTR();
						m_nSCCTRL &= ~SCCTRL_RETTOP;
						continue;
					}
				}
			}
			else
			{
				//Suspend transfer
				break;
			}

			if(m_CHCR.nTTE == 1)
			{
				m_CHCR.nReserved0 = 0;
				if(m_pReceive(m_nTADR, 1, 0, true) != 1)
				{
					//Device didn't receive DmaTag, break for now
					m_CHCR.nReserved0 = 1;
					break;
				}
			}
		}

		//Half-Life does this...
		if(m_nTADR == 0)
		{
			ClearSTR();
			continue;
		}

		uint64 nTag = m_dmac.FetchDMATag(m_nTADR);

		//Save higher 16 bits of tag into CHCR
		m_CHCR.nTAG = nTag >> 16;
		//m_nCHCR &= ~0xFFFF0000;
		//m_nCHCR |= nTag & 0xFFFF0000;

		uint8 nID = (uint8)((nTag >> 28) & 0x07);

		switch(nID)
		{
		case 0:
			//REFE - Data to transfer is pointer in memory address, transfer is done
			m_nMADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= m_nTADR + 0x10;
			break;
		case 1:
			//CNT - Data to transfer is after the tag, next tag is after the data
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)(nTag & 0xFFFF);
			m_nTADR		= (m_nQWC * 0x10) + m_nMADR;
			break;
		case 2:
			//NEXT - Transfers data after tag, next tag is at position in ADDR field
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			break;
		case 3:
		case 4:
			//REF/REFS - Data to transfer is pointed in memory address, next tag is after this tag
			m_nMADR		= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_nQWC		= (uint32)((nTag >>   0) & 0x0000FFFF);
			m_nTADR		= m_nTADR + 0x10;
			break;
		case 5:
			//CALL - Transfers QWC after the tag, saves next address in ASR, TADR = ADDR
			assert(m_CHCR.nASP < 2);
			m_nMADR				= m_nTADR + 0x10;
			m_nQWC				= (uint32)(nTag & 0xFFFF);
			m_nASR[m_CHCR.nASP]	= m_nMADR + (m_nQWC * 0x10);
			m_nTADR				= (uint32)((nTag >>  32) & 0xFFFFFFFF);
			m_CHCR.nASP++;
			break;
		case 6:
			//RET - Transfers QWC after the tag, pops TADR from ASR
			m_nMADR = m_nTADR + 0x10;
			m_nQWC = (uint32)(nTag & 0xFFFF);
			if(m_CHCR.nASP > 0)
			{
				m_CHCR.nASP--;
				m_nTADR = m_nASR[m_CHCR.nASP];
			}
			else
			{
				m_nSCCTRL |= SCCTRL_RETTOP;
			}
			break;
		case 7:
			//END - Data to transfer is after the tag, transfer is finished
			m_nMADR		= m_nTADR + 0x10;
			m_nQWC		= (uint32)(nTag & 0xFFFF);
			break;
		default:
			m_nQWC = 0;
			assert(0);
			break;
		}

		if(m_nQWC != 0)
		{
			uint32 nRecv = m_pReceive(m_nMADR, m_nQWC, 0, false);

			m_nMADR		+= nRecv * 0x10;
			m_nQWC		-= nRecv;
		}
	}
}

void CChannel::SetReceiveHandler(const DmaReceiveHandler& handler)
{
	m_pReceive = handler;
}

void CChannel::ClearSTR()
{
	m_CHCR.nSTR = ~m_CHCR.nSTR;

	//Set interrupt
	m_dmac.m_D_STAT |= (1 << m_nNumber);

	m_dmac.UpdateCpCond();
}
<|endoftext|>


<commit_before>#pragma once

/*
 * A bucket-chaining hash table.
 */

#include "spinlock.h"
#include "seqlock.hh"
#include "lockwrap.hh"
#include "hash.hh"
#include "ilist.hh"

template<class K, class V>
class chainhash {
private:
  struct item : public rcu_freed {
    item(const K& k, const V& v)
      : rcu_freed("chainhash::item", this, sizeof(*this)),
        key(k), val(v) {}
    void do_gc() override { delete this; }
    NEW_DELETE_OPS(item);

    islink<item> link;
    seqcount<u32> seq;
    const K key;
    V val;
  };

  struct bucket {
    spinlock lock;
    islist<item, &item::link> chain;

    ~bucket() {
      while (!chain.empty()) {
        item *i = &chain.front();
        chain.pop_front();
        gc_delayed(i);
      }
    }
  };

  u64 nbuckets_;
  bool dead_;
  bucket* buckets_;

public:
  chainhash(u64 nbuckets) : nbuckets_(nbuckets), dead_(false) {
    buckets_ = new bucket[nbuckets_];
    assert(buckets_);
  }

  ~chainhash() {
    delete[] buckets_;
  }

  NEW_DELETE_OPS(chainhash);

  bool insert(const K& k, const V& v) {
    if (dead_ || lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    if (dead_)
      return false;

    for (const item& i: b->chain)
      if (i.key == k)
        return false;

    b->chain.push_front(new item(k, v));
    return true;
  }

  bool remove(const K& k, const V& v) {
    if (!lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    auto i = b->chain.before_begin();
    auto end = b->chain.end();
    for (;;) {
      auto prev = i;
      ++i;
      if (i == end)
        return false;
      if (i->key == k && i->val == v) {
        b->chain.erase_after(prev);
        gc_delayed(&*i);
        return true;
      }
    }
  }

  bool replace(const K& k, const V& vold, const V& vnew) {
    if (!lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    for (item& i: b->chain) {
      if (i.key == k) {
        if (i.val != vold)
          return false;
        auto w = i.seq.write_begin();
        i.val = vnew;
        return true;
      }
    }

    return false;
  }

  bool enumerate(const K* prev, K* out) const {
    scoped_gc_epoch rcu_read;

    bool prevbucket = (prev != nullptr);
    for (u64 i = prev ? hash(*prev) % nbuckets_ : 0; i < nbuckets_; i++) {
      bucket* b = &buckets_[i];
      bool found = false;
      for (const item& i: b->chain) {
        if ((!prevbucket || *prev < i.key) && (!found || i.key < *out)) {
          *out = i.key;
          found = true;
        }
      }
      if (found)
        return true;
      prevbucket = false;
    }

    return false;
  }

  bool lookup(const K& k, V* vptr = nullptr) const {
    scoped_gc_epoch rcu_read;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    for (const item& i: b->chain) {
      if (i.key != k)
        continue;
      if (vptr)
        *vptr = *seq_reader<V>(&i.val, &i.seq);
      return true;
    }
    return false;
  }

  bool remove_and_kill(const K& k, const V& v) {
    if (dead_)
      return false;

    for (u64 i = 0; i < nbuckets_; i++)
      for (const item& ii: buckets_[i].chain)
        if (ii.key != k || ii.val != v)
          return false;

    for (u64 i = 0; i < nbuckets_; i++)
      buckets_[i].lock.acquire();

    bool killed = !dead_;
    for (u64 i = 0; i < nbuckets_; i++)
      for (const item& ii: buckets_[i].chain)
        if (ii.key != k || ii.val != v)
          killed = false;

    if (killed) {
      dead_ = true;
      bucket* b = &buckets_[hash(k) % nbuckets_];
      item* i = &b->chain.front();
      assert(i->key == k && i->val == v);
      b->chain.pop_front();
      gc_delayed(i);
    }

    for (u64 i = 0; i < nbuckets_; i++)
      buckets_[i].lock.release();

    return killed;
  }

  bool killed() const {
    return dead_;
  }
};
<commit_msg>perhaps improve file system scalability?<commit_after>#pragma once

/*
 * A bucket-chaining hash table.
 */

#include "spinlock.h"
#include "seqlock.hh"
#include "lockwrap.hh"
#include "hash.hh"
#include "ilist.hh"

template<class K, class V>
class chainhash {
private:
  struct item : public rcu_freed {
    item(const K& k, const V& v)
      : rcu_freed("chainhash::item", this, sizeof(*this)),
        key(k), val(v) {}
    void do_gc() override { delete this; }
    NEW_DELETE_OPS(item);

    islink<item> link;
    seqcount<u32> seq;
    const K key;
    V val;
  };

  struct bucket {
    spinlock lock __mpalign__;
    islist<item, &item::link> chain;

    ~bucket() {
      while (!chain.empty()) {
        item *i = &chain.front();
        chain.pop_front();
        gc_delayed(i);
      }
    }
  };

  u64 nbuckets_;
  bool dead_;
  bucket* buckets_;

public:
  chainhash(u64 nbuckets) : nbuckets_(nbuckets), dead_(false) {
    buckets_ = new bucket[nbuckets_];
    assert(buckets_);
  }

  ~chainhash() {
    delete[] buckets_;
  }

  NEW_DELETE_OPS(chainhash);

  bool insert(const K& k, const V& v) {
    if (dead_ || lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    if (dead_)
      return false;

    for (const item& i: b->chain)
      if (i.key == k)
        return false;

    b->chain.push_front(new item(k, v));
    return true;
  }

  bool remove(const K& k, const V& v) {
    if (!lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    auto i = b->chain.before_begin();
    auto end = b->chain.end();
    for (;;) {
      auto prev = i;
      ++i;
      if (i == end)
        return false;
      if (i->key == k && i->val == v) {
        b->chain.erase_after(prev);
        gc_delayed(&*i);
        return true;
      }
    }
  }

  bool replace(const K& k, const V& vold, const V& vnew) {
    if (!lookup(k))
      return false;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    scoped_acquire l(&b->lock);

    for (item& i: b->chain) {
      if (i.key == k) {
        if (i.val != vold)
          return false;
        auto w = i.seq.write_begin();
        i.val = vnew;
        return true;
      }
    }

    return false;
  }

  bool enumerate(const K* prev, K* out) const {
    scoped_gc_epoch rcu_read;

    bool prevbucket = (prev != nullptr);
    for (u64 i = prev ? hash(*prev) % nbuckets_ : 0; i < nbuckets_; i++) {
      bucket* b = &buckets_[i];
      bool found = false;
      for (const item& i: b->chain) {
        if ((!prevbucket || *prev < i.key) && (!found || i.key < *out)) {
          *out = i.key;
          found = true;
        }
      }
      if (found)
        return true;
      prevbucket = false;
    }

    return false;
  }

  bool lookup(const K& k, V* vptr = nullptr) const {
    scoped_gc_epoch rcu_read;

    bucket* b = &buckets_[hash(k) % nbuckets_];
    for (const item& i: b->chain) {
      if (i.key != k)
        continue;
      if (vptr)
        *vptr = *seq_reader<V>(&i.val, &i.seq);
      return true;
    }
    return false;
  }

  bool remove_and_kill(const K& k, const V& v) {
    if (dead_)
      return false;

    for (u64 i = 0; i < nbuckets_; i++)
      for (const item& ii: buckets_[i].chain)
        if (ii.key != k || ii.val != v)
          return false;

    for (u64 i = 0; i < nbuckets_; i++)
      buckets_[i].lock.acquire();

    bool killed = !dead_;
    for (u64 i = 0; i < nbuckets_; i++)
      for (const item& ii: buckets_[i].chain)
        if (ii.key != k || ii.val != v)
          killed = false;

    if (killed) {
      dead_ = true;
      bucket* b = &buckets_[hash(k) % nbuckets_];
      item* i = &b->chain.front();
      assert(i->key == k && i->val == v);
      b->chain.pop_front();
      gc_delayed(i);
    }

    for (u64 i = 0; i < nbuckets_; i++)
      buckets_[i].lock.release();

    return killed;
  }

  bool killed() const {
    return dead_;
  }
};
<|endoftext|>


<commit_before>// ft2232spi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif

/* Include D2XX header*/
#include "ftd2xx.h"

#pragma comment(lib, "FTD2XX.lib")
#pragma comment(lib, "libMPSSE.lib")

/* Include libMPSSE header */
#include "libMPSSE_spi.h"

/* Helper macros */

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Definitions */
#define PROG_BUFFER_SIZE        4000000
#define SPI_DEVICE_BUFFER_SIZE		256
#define CHANNEL_TO_OPEN			0	/*0 for first available channel, 1 for next... */
#define SPI_WRITE_COMPLETION_RETRY 100
#define SPI_OPTS               SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE
#define GPIO_INIT			   GPIO_DIR /* Everything that's an output should be set high */
//#define RESET_CHIP
#define TEST_COMMUNICATION

int _tmain(int argc, _TCHAR* argv[]) {
	FT_STATUS ftStatus;
	FT_HANDLE ftHandle;
	uint8* wBuffer = new uint8[PROG_BUFFER_SIZE];
	uint8* rBuffer = new uint8[SPI_DEVICE_BUFFER_SIZE];

	FILE* fileHandle;
	size_t fileSize;
	FT_STATUS status = FT_OK;
	FT_DEVICE_LIST_INFO_NODE devList = {0};
	ChannelConfig channelConf = {0};
	uint8 address = 0;
	uint32 channels = 0;
	uint32 sizeTransferred;
	uint16 data = 0;
	uint8 i = 0;

	if (wBuffer == NULL) {
		printf("Couln't allocate memeory for write buffer.\r\n");
		exit(1);
	}
	if (rBuffer == NULL) {
		printf("Couln't allocate memeory for read buffer.\r\n");
		exit(1);
	}

	channelConf.ClockRate = 3000000;
	channelConf.LatencyTimer = 255;
	channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
	channelConf.Pin = 0x80B080B0;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/
	channelConf.reserved = 0;

	/* init library */
#ifdef _MSC_VER
	Init_libMPSSE();
#endif
	status = SPI_GetNumChannels(&channels);
	APP_CHECK_STATUS(status);
	printf("Number of available SPI channels = %d\n",(int)channels);

	if(channels>0)
	{
		/* Open the first available channel */
		status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
		APP_CHECK_STATUS(status);
		printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);

		status = SPI_InitChannel(ftHandle,&channelConf);
		APP_CHECK_STATUS(status);

#ifdef RESET_CHIP
		// Reset the FPGA by setting a dummy pin as the chip select with active high which sets both SS and CRESET_B low
		status = SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS5);
		APP_CHECK_STATUS(status);
		SPI_Write(ftHandle, wBuffer, 1, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);

		Sleep(1);

		// Change the chip select back to the actual chip select
		SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW);
		APP_CHECK_STATUS(status);

		Sleep(1);
#endif

		// Write some data for the lattice iCE40Ultra EVK demo

		fileHandle = fopen("C:\\Users\\DanielCascner\\Documents\\peripherals\\peripherals_Implmnt\\sbt\\outputs\\bitmap\\top_bitmap.bin", "rb");
		if (fileHandle == NULL) {
			printf("Couldn't open programming file\r\n");
			exit(1);
		}
		fseek(fileHandle, 0, SEEK_END);
		fileSize   = ftell(fileHandle);
		printf("Programming file is %d bytes\r\n", fileSize);
		fseek(fileHandle, 0, SEEK_SET);

		sizeTransferred = fread(wBuffer, sizeof(uint8), fileSize, fileHandle);
		if (sizeTransferred != fileSize) {
			printf("Didn't read full programming file %d < %d\r\n", sizeTransferred, fileSize);
			exit(1);
		}
		for (int i=0; i<50; ++i) wBuffer[sizeTransferred++] = 0; // Add dummy bytes

		status = SPI_Write(ftHandle, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Transferred %d bytes\r\n", sizeTransferred);
		unsigned long retry = 0;
		bool state=FALSE;
		SPI_IsBusy(ftHandle,&state);
		while((FALSE==state) && (retry<SPI_WRITE_COMPLETION_RETRY))
		{
			printf("SPI device is busy(%u)\n",(unsigned)retry);
			SPI_IsBusy(ftHandle,&state);
			retry++;
		}

#ifdef TEST_COMMUNICATION
		Sleep(10);

		for (sizeTransferred = 0; sizeTransferred < 10; sizeTransferred++) wBuffer[sizeTransferred] = sizeTransferred;
		status = SPI_ReadWrite(ftHandle, rBuffer, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Transferred %d bytes\r\n", sizeTransferred);
		rBuffer[sizeTransferred] = 0;
		printf("Received %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \r\n", rBuffer[0], rBuffer[1], rBuffer[2], rBuffer[3], rBuffer[4], rBuffer[5], rBuffer[6], rBuffer[7], rBuffer[8], rBuffer[9]);

#endif
		status = SPI_CloseChannel(ftHandle);
	}

	delete wBuffer;
	delete rBuffer;

#ifdef _MSC_VER
	Cleanup_libMPSSE();
#endif

#ifndef __linux__
	system("pause");
#endif
	return 0;
}

<commit_msg>Working test code<commit_after>// ft2232spi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif

/* Include D2XX header*/
#include "ftd2xx.h"

#pragma comment(lib, "FTD2XX.lib")
#pragma comment(lib, "libMPSSE.lib")

/* Include libMPSSE header */
#include "libMPSSE_spi.h"

/* Helper macros */

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Definitions */
#define SPI_DEVICE_BUFFER_SIZE		256
#define CHANNEL_TO_OPEN			0	/*0 for first available channel, 1 for next... */
#define SPI_WRITE_COMPLETION_RETRY 100
#define SPI_OPTS               SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE
#define GPIO_INIT			   GPIO_DIR /* Everything that's an output should be set high */
//#define RESET_CHIP
#define TEST_COMMUNICATION

int _tmain(int argc, _TCHAR* argv[]) {
	FT_STATUS ftStatus;
	FT_HANDLE ftHandle;
	uint8* wBuffer = new uint8[SPI_DEVICE_BUFFER_SIZE];
	uint8* rBuffer = new uint8[SPI_DEVICE_BUFFER_SIZE];

	FILE* fileHandle;
	size_t fileSize;
	FT_STATUS status = FT_OK;
	FT_DEVICE_LIST_INFO_NODE devList = {0};
	ChannelConfig channelConf = {0};
	uint8 address = 0;
	uint32 channels = 0;
	uint32 sizeTransferred;
	uint16 data = 0;
	uint8 i = 0;

	if (wBuffer == NULL) {
		printf("Couln't allocate memeory for write buffer.\r\n");
		exit(1);
	}
	if (rBuffer == NULL) {
		printf("Couln't allocate memeory for read buffer.\r\n");
		exit(1);
	}

	channelConf.ClockRate = 3000000;
	channelConf.LatencyTimer = 255;
	channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
	channelConf.Pin = 0xF0B0F0B0;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/
	channelConf.reserved = 0;

	/* init library */
#ifdef _MSC_VER
	Init_libMPSSE();
#endif
	status = SPI_GetNumChannels(&channels);
	APP_CHECK_STATUS(status);
	printf("Number of available SPI channels = %d\n",(int)channels);

	if(channels>0)
	{
		/* Open the first available channel */
		status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
		APP_CHECK_STATUS(status);
		printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);

		status = SPI_InitChannel(ftHandle,&channelConf);
		APP_CHECK_STATUS(status);

		for (sizeTransferred = 0; sizeTransferred < 10; sizeTransferred++) wBuffer[sizeTransferred] = sizeTransferred;
		status = SPI_ReadWrite(ftHandle, rBuffer, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Transferred %d bytes\r\n", sizeTransferred);
		rBuffer[sizeTransferred] = 0;
		printf("Received %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \r\n", rBuffer[0], rBuffer[1], rBuffer[2], rBuffer[3], rBuffer[4], rBuffer[5], rBuffer[6], rBuffer[7], rBuffer[8], rBuffer[9]);

	}

	delete wBuffer;
	delete rBuffer;

#ifdef _MSC_VER
	Cleanup_libMPSSE();
#endif

#ifndef __linux__
	system("pause");
#endif
	return 0;
}

<|endoftext|>