<commit_before>/**
 * @file
 */
#include "ste.h"
#define MAX_ERROR_MSG 0x1000

using namespace std;
using namespace MNRL;

/*
 *
 */
STE::STE(string id, string symbol_set, string strt) : Element(id),

                                                      latched(false) {

    setStart(strt);
    setSymbolSet(symbol_set);

    for(uint32_t i = 0; i < 256; i++) {
        bit_column.set(i,0);
    }

    parseSymbolSet(bit_column, symbol_set);

}

STE::~STE() {

    // for some reason this is segfaulting within regex.h

}

/*
 *
 */
bool STE::setSymbolSet(string symbol_set) {

    this->symbol_set = symbol_set;
    sanitizeSymbolSet();
    return true;
}

/*
 *
 */
string STE::getSymbolSet() {

    return symbol_set;
}

/*
 *
 */
string STE::getRegexSymbolSet() {

    if(symbol_set.compare("*") == 0)
        return ".";
    else
        return symbol_set;
}

/*
 *
 */
bool STE::setStart(string strt) {

    if(strt.compare("start-of-data") == 0) {
        start = START_OF_DATA;
    } else if (strt.compare("all-input") == 0) {
        start = ALL_INPUT;
    } else {
        start = NONE;
    }

    return true;
}

/*
 *
 */
bool STE::setStart(Start s) {

    start = s;

    return true;
}

/*
 *
 */
STE::Start STE::getStart() {

    return start;
}

/*
 *
 */
string STE::getStringStart() {

    if(start == START_OF_DATA){
        return "start-of-data";
    }else if(start == ALL_INPUT){
        return "all-input";
    }else{
        return "none";
    }

}

/*
 *
 */
bool STE::isStart() {

    bool result = false;

    if(start != NONE){
        result = true;
    }

    return result;
}

/*
 *
 */
bool STE::startIsAllInput() {

    bool result = false;

    if(start == ALL_INPUT){
        result = true;
    }

    return result;
}

/*
 *
 */
bool STE::startIsStartOfData() {

    return (start == START_OF_DATA);
}

/*
 *
 */
bool STE::isSpecialElement() {

    return false;
}

/*
 *
 */
bool STE::isActivateNoInput() {

    if(isStart()){
        return true;
    }else{
        return false;
    }
}

/*
 *
 */
bool STE::deactivate() {

    bool retval = true;

    if(latched) {
        retval = false;
    } else {
        activated = false;
    }

    return retval;
}

/*
 *
 */
vector<uint32_t> STE::getIntegerSymbolSet() {

    vector<uint32_t> ret;
    //this is lazy and slow, but sososososo clean and easy
    //try to match on every character. If we match
    // add to the return set
    for(uint32_t i = 0; i < 256; i++) {
        if(match((uint8_t)i))
            ret.push_back(i);

    }

    return ret;
}

/*
 *
 */
string STE::toString() {

    string s("");

    s.append("STE: id=");
    s.append(id);
    s.append(" symbol-set=");
    s.append(symbol_set);
    s.append(" start=");
    if(start == ALL_INPUT){
        s.append("all-input");
    }else if( start == START_OF_DATA) {
        s.append("start-of-data");
    } else {
        s.append("none");
    }

    s.append("\n\t");
    s.append("activate-on-match=\n\t  ");
  //  for(string s2 : outputs) {
  //      s.append(s2);
  //      s.append("\n\t  ");
  //  }
    s.append("reporting=");
    if(reporting)
        s.append("true");
    else
        s.append("false");
    s.append("\n\t  ");
    s.append("enabled=");
    if(isEnabled()) {
        s.append("true");
    } else {
        s.append("false");
    }

    s.append("\nINPUTS:\n");
    for(auto s2 : inputs) {
        s.append(s2.first);
        s.append("\n");
    }
    return s;
}

/**
 * Returns a string representation of this node as an ANML state transition element.
 */
string STE::toANML() {

    string s("<state-transition-element ");

    s.append("id=\"");
    s.append(id);
    s.append("\" ");
    s.append(" symbol-set=\"");
    s.append(symbol_set);
    s.append("\" ");
    s.append(" start=\"");
    if(start == ALL_INPUT){
        s.append("all-input");
    }else if( start == START_OF_DATA) {
        s.append("start-of-data");
    } else {
        s.append("none");
    }
    s.append("\">\n");

    if(reporting){
        if(!report_code.empty()){
            s.append("\t<report-on-match reportcode=\"");
            s.append(report_code);
            s.append("\"/>\n");
        }else{
            s.append("\t<report-on-match/>\n");
        }
    }

    for(string s2 : outputs) {
        s.append("\t<activate-on-match element=\"");
        s.append(s2);
        s.append("\"/>\n");
    }

    s.append("</state-transition-element>");

    return s;
}

/**
 * Returns a MNRL object corresponding to this STE.
 * Note: that this doesn't contain the connections
 */
shared_ptr<MNRLNode> STE::toMNRLObj() {

    MNRLDefs::EnableType en;
    switch(start) {
        case NONE:
            en = MNRLDefs::EnableType::ENABLE_ON_ACTIVATE_IN;
            break;
        case START_OF_DATA:
            en = MNRLDefs::EnableType::ENABLE_ON_START_AND_ACTIVATE_IN;
            break;
        case ALL_INPUT:
            en = MNRLDefs::EnableType::ENABLE_ALWAYS;
            break;
    }

    shared_ptr<MNRLHState> s =
        shared_ptr<MNRLHState>(new MNRLHState(
            symbol_set,
            en,
            id,
            reporting,
            false, // latched
            report_code,
            shared_ptr<map<string,string>>(new map<string,string>())
        ));

    return s;
}

/**
 *
 */
bool STE::setBitColumn(bitset<256> new_column){

    // clear column
    bit_column.reset();

    // set all bits in our column to input column
    for(size_t i = 0; i < 256; i++){
        bit_column[i] = new_column[i];
    }

    // update string version of charset
    setSymbolSet(bitsetToCharset(bit_column));

    return true;
}

/**
 *
 */
bitset<256> STE::getBitColumn(){
    return bit_column;
}

/**
 * Adds a character to a symbol set.
 *  If symbol set is wrapped with brackets, they are removed
 *  and then added after the symbol is added.
 */
bool STE::addSymbolToSymbolSet(uint32_t symbol) {

    bool already_exists;
    already_exists = bit_column.test(symbol);

    if(!already_exists){

        // add to bit column
        bit_column.set(symbol);

        setSymbolSet(bitsetToCharset(bit_column));
    }

    return already_exists;
}

/**
 * Implements compare for STEs (greater than)
 */
int STE::compare(STE *other) {

    // check bit vector
    //bool * other_column = other->getBitColumn();
    bitset<256> other_column = other->getBitColumn();
    for(int i = 0; i < 256; i++) {
        // if we find a true before we find a true in the other column, return true
        if(bit_column.test(i) == true && other_column.test(i) == false) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return 1;
        }else if(bit_column.test(i) == false && other_column.test(i) == true) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return -1;
        }
   }

    // check start
    // Greater conditions
     bool debug_out = false;
    if(getStart() != other->getStart()){
        if(getStart() == ALL_INPUT){
            return 1;
        }
        if((getStart() == START_OF_DATA) && (other->getStart() == NONE)){
            return 1;
        }
        // Less conditions
        if(getStart() == NONE){
            return -1;
        }
        if((getStart() == START_OF_DATA) && (other->getStart() == ALL_INPUT)){
            return -1;
        }
    }else {
        if(getStart() > 0 || other->getStart() > 0){
            //cout << "STARTS EQUALED: " << getStart() << endl;
            //debug_out = true;
        }
    }

    // check report

    if(isReporting() == true && other->isReporting() == false) {
        if(debug_out)
            cout << "report mismatch" << endl;
        return 1;
    }else if(isReporting() == false && other->isReporting() == true) {
        if(debug_out)
            cout << "report mismatch2" << endl;
        return -1;
        //never merge reports
    }
    // never merge two reports
    // NOTE: this is *not* the behavior of the micron compiler TODO
    else if(isReporting() || other->isReporting()){
        if(debug_out)
            cout << "report mismatch3" << endl;
        return -1;
    }

    // check input sizes
    if(inputs.size() != other->getInputs().size()) {

        //can merge start states that self reference
        if(inputs.size() > other->getInputs().size()){
        if(debug_out)
            cout << "input size mismatch1" << endl;
            return 1;
        } else {
        if(debug_out)
            cout << "input size mismatch2" << endl;
            return -1;
        }
    }

    // for each input key, check if output has it;
    // if it doesn't, just say we are greater;
    // disregard self references because these are safe
    // TODO:: this seems very inefficient but isn't too slow in practice

    vector<string> keys;
    vector<string> other_keys;

    bool input_check = false;
    for(auto e : inputs) {
        if(e.first.compare(getId()) != 0){ // filter self loop
            keys.push_back(e.first);
        }
    }
    sort(keys.begin(), keys.end());

    for(auto e : other->getInputs()) {
        if(e.first.compare(other->getId()) != 0) { // filter self loop
            other_keys.push_back(e.first);
        }
    }
    sort(other_keys.begin(), other_keys.end());

    // check input sizes again
    if(keys.size() != other_keys.size()) {
        if(debug_out)
        cout << "inputs don't match" << endl;
        if(keys.size() > other_keys.size())
            return 1;
        else
            return -1;
    }

    // compare sorted input keys, returning lexocographic ordering of first mismatch
    /*if(debug_out){
        for(int i = 0; i < keys.size(); i++){
    	    cout << keys[i] << "asf" << endl;
            cout << other_keys[i] << endl;
        }
    }
*/
    for(int i = 0; i < keys.size(); i++){
	if(debug_out)
	cout<< keys[i] << " " << other_keys[i]<<endl;
        int comp_result = keys[i].compare(other_keys[i]);
        if(comp_result > 0){
            if(debug_out){
                cout << "inputs don't match2" << endl;
            }
            return 1;

        }else if(comp_result < 0) {
        if(debug_out)
            cout << "inputs don't match3" << endl;
            return -1;
        }
    }

    // match returns 0
    /*
    cout << "*************" << endl;
    cout << toString() << "\n" << other->toString();
    cout << "*************" << endl;
    */
    /*
    if(symbol_set.compare(other->getSymbolSet()) != 0){
        cout << "MISMATCH" << endl;
        cout << "*************" << endl;
        cout << toString() << "\n" << other->toString();
        for(int i = 0; i < 256; i++){
            cout << bit_column.test(i) << endl;
        }
        cout << "*************" << endl;

    }
    */

    return 0;
}

/**
 * Implements compare for STE columns (greater than)
 */
int STE::compareSymbolSet(STE *other) {

    // check bit vector
    //bool * other_column = other->getBitColumn();
    bitset<256> other_column = other->getBitColumn();
    for(int i = 0; i < 256; i++) {
        // if we find a true before we find a true in the other column, return true
        if(bit_column[i] == true && other_column[i] == false) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return 1;
        }else if(bit_column[i] == false && other_column[i] == true) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return -1;
        }
   }

    return 0;
}

/**
 *
 */
STE *STE::clone() {

    STE * clone = new STE(getId(), getSymbolSet(), getStringStart());

    if(isReporting()){
        clone->setReporting(true);
        clone->setReportCode(getReportCode());
    }

    // id's are the same, but we don't want that
    // append unique int id to string id;
    string new_id = clone->getId() +"_" + to_string(clone->getIntId());
    clone->setId(new_id);

    /*
    // add all inputs
    for(auto in : inputs){
        clone->addInput(in.first);
    }

    // add all outputs
    for(auto out : getOutputSTEPointers()){
        clone->addOutput(out.second);
        clone->addOutputPointer(out.first, out.second);
    }
    */

    return clone;
}

/**
 *
 */
void STE::follow(uint32_t character, set<STE*> *follow_set){

    for(auto e : outputSTEPointers){

        STE *s = static_cast<STE*>(e.first);
        if(s->match(character))
            follow_set->insert(s);
    }
}

/**
 *
 */
ElementType STE::getType() {

    return ElementType::STE_T;
}

/**
 * Replaces illegal XML chars in charset with hex version
 */
void STE::sanitizeSymbolSet() {

    // &
    size_t loc = symbol_set.find("&");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x26").length(), "\\x26");
        loc = symbol_set.find("&");
    }

    // <
    loc = symbol_set.find("<");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x3C").length(), "\\x3C");
        loc = symbol_set.find("<");
    }

    // "
    loc = symbol_set.find("\"");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x22").length(), "\\x22");
        loc = symbol_set.find("\"");
    }
}
<commit_msg>Added ANML symbol set sanitization that will prevent MNRL symbol sets with illegal XML characters from making it into emitted ANML.<commit_after>/**
 * @file
 */
#include "ste.h"
#define MAX_ERROR_MSG 0x1000

using namespace std;
using namespace MNRL;

/*
 *
 */
STE::STE(string id, string symbol_set, string strt) : Element(id),

                                                      latched(false) {

    setStart(strt);
    setSymbolSet(symbol_set);

    for(uint32_t i = 0; i < 256; i++) {
        bit_column.set(i,0);
    }

    parseSymbolSet(bit_column, symbol_set);

}

STE::~STE() {

    // for some reason this is segfaulting within regex.h

}

/*
 *
 */
bool STE::setSymbolSet(string symbol_set) {

    this->symbol_set = symbol_set;
    sanitizeSymbolSet();
    return true;
}

/*
 *
 */
string STE::getSymbolSet() {

    return symbol_set;
}

/*
 *
 */
string STE::getRegexSymbolSet() {

    if(symbol_set.compare("*") == 0)
        return ".";
    else
        return symbol_set;
}

/*
 *
 */
bool STE::setStart(string strt) {

    if(strt.compare("start-of-data") == 0) {
        start = START_OF_DATA;
    } else if (strt.compare("all-input") == 0) {
        start = ALL_INPUT;
    } else {
        start = NONE;
    }

    return true;
}

/*
 *
 */
bool STE::setStart(Start s) {

    start = s;

    return true;
}

/*
 *
 */
STE::Start STE::getStart() {

    return start;
}

/*
 *
 */
string STE::getStringStart() {

    if(start == START_OF_DATA){
        return "start-of-data";
    }else if(start == ALL_INPUT){
        return "all-input";
    }else{
        return "none";
    }

}

/*
 *
 */
bool STE::isStart() {

    bool result = false;

    if(start != NONE){
        result = true;
    }

    return result;
}

/*
 *
 */
bool STE::startIsAllInput() {

    bool result = false;

    if(start == ALL_INPUT){
        result = true;
    }

    return result;
}

/*
 *
 */
bool STE::startIsStartOfData() {

    return (start == START_OF_DATA);
}

/*
 *
 */
bool STE::isSpecialElement() {

    return false;
}

/*
 *
 */
bool STE::isActivateNoInput() {

    if(isStart()){
        return true;
    }else{
        return false;
    }
}

/*
 *
 */
bool STE::deactivate() {

    bool retval = true;

    if(latched) {
        retval = false;
    } else {
        activated = false;
    }

    return retval;
}

/*
 *
 */
vector<uint32_t> STE::getIntegerSymbolSet() {

    vector<uint32_t> ret;
    //this is lazy and slow, but sososososo clean and easy
    //try to match on every character. If we match
    // add to the return set
    for(uint32_t i = 0; i < 256; i++) {
        if(match((uint8_t)i))
            ret.push_back(i);

    }

    return ret;
}

/*
 *
 */
string STE::toString() {

    string s("");

    s.append("STE: id=");
    s.append(id);
    s.append(" symbol-set=");
    s.append(symbol_set);
    s.append(" start=");
    if(start == ALL_INPUT){
        s.append("all-input");
    }else if( start == START_OF_DATA) {
        s.append("start-of-data");
    } else {
        s.append("none");
    }

    s.append("\n\t");
    s.append("activate-on-match=\n\t  ");
  //  for(string s2 : outputs) {
  //      s.append(s2);
  //      s.append("\n\t  ");
  //  }
    s.append("reporting=");
    if(reporting)
        s.append("true");
    else
        s.append("false");
    s.append("\n\t  ");
    s.append("enabled=");
    if(isEnabled()) {
        s.append("true");
    } else {
        s.append("false");
    }

    s.append("\nINPUTS:\n");
    for(auto s2 : inputs) {
        s.append(s2.first);
        s.append("\n");
    }
    return s;
}

/**
 * Returns a string representation of this node as an ANML state transition element.
 */
string STE::toANML() {

    string s("<state-transition-element ");

    s.append("id=\"");
    s.append(id);
    s.append("\" ");
    s.append(" symbol-set=\"");
    s.append(symbol_set);
    s.append("\" ");
    s.append(" start=\"");
    if(start == ALL_INPUT){
        s.append("all-input");
    }else if( start == START_OF_DATA) {
        s.append("start-of-data");
    } else {
        s.append("none");
    }
    s.append("\">\n");

    if(reporting){
        if(!report_code.empty()){
            s.append("\t<report-on-match reportcode=\"");
            s.append(report_code);
            s.append("\"/>\n");
        }else{
            s.append("\t<report-on-match/>\n");
        }
    }

    for(string s2 : outputs) {
        s.append("\t<activate-on-match element=\"");
        s.append(s2);
        s.append("\"/>\n");
    }

    s.append("</state-transition-element>");

    return s;
}

/**
 * Returns a MNRL object corresponding to this STE.
 * Note: that this doesn't contain the connections
 */
shared_ptr<MNRLNode> STE::toMNRLObj() {

    MNRLDefs::EnableType en;
    switch(start) {
        case NONE:
            en = MNRLDefs::EnableType::ENABLE_ON_ACTIVATE_IN;
            break;
        case START_OF_DATA:
            en = MNRLDefs::EnableType::ENABLE_ON_START_AND_ACTIVATE_IN;
            break;
        case ALL_INPUT:
            en = MNRLDefs::EnableType::ENABLE_ALWAYS;
            break;
    }

    shared_ptr<MNRLHState> s =
        shared_ptr<MNRLHState>(new MNRLHState(
            symbol_set,
            en,
            id,
            reporting,
            false, // latched
            report_code,
            shared_ptr<map<string,string>>(new map<string,string>())
        ));

    return s;
}

/**
 *
 */
bool STE::setBitColumn(bitset<256> new_column){

    // clear column
    bit_column.reset();

    // set all bits in our column to input column
    for(size_t i = 0; i < 256; i++){
        bit_column[i] = new_column[i];
    }

    // update string version of charset
    setSymbolSet(bitsetToCharset(bit_column));

    return true;
}

/**
 *
 */
bitset<256> STE::getBitColumn(){
    return bit_column;
}

/**
 * Adds a character to a symbol set.
 *  If symbol set is wrapped with brackets, they are removed
 *  and then added after the symbol is added.
 */
bool STE::addSymbolToSymbolSet(uint32_t symbol) {

    bool already_exists;
    already_exists = bit_column.test(symbol);

    if(!already_exists){

        // add to bit column
        bit_column.set(symbol);

        setSymbolSet(bitsetToCharset(bit_column));
    }

    return already_exists;
}

/**
 * Implements compare for STEs (greater than)
 */
int STE::compare(STE *other) {

    // check bit vector
    //bool * other_column = other->getBitColumn();
    bitset<256> other_column = other->getBitColumn();
    for(int i = 0; i < 256; i++) {
        // if we find a true before we find a true in the other column, return true
        if(bit_column.test(i) == true && other_column.test(i) == false) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return 1;
        }else if(bit_column.test(i) == false && other_column.test(i) == true) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return -1;
        }
   }

    // check start
    // Greater conditions
     bool debug_out = false;
    if(getStart() != other->getStart()){
        if(getStart() == ALL_INPUT){
            return 1;
        }
        if((getStart() == START_OF_DATA) && (other->getStart() == NONE)){
            return 1;
        }
        // Less conditions
        if(getStart() == NONE){
            return -1;
        }
        if((getStart() == START_OF_DATA) && (other->getStart() == ALL_INPUT)){
            return -1;
        }
    }else {
        if(getStart() > 0 || other->getStart() > 0){
            //cout << "STARTS EQUALED: " << getStart() << endl;
            //debug_out = true;
        }
    }

    // check report

    if(isReporting() == true && other->isReporting() == false) {
        if(debug_out)
            cout << "report mismatch" << endl;
        return 1;
    }else if(isReporting() == false && other->isReporting() == true) {
        if(debug_out)
            cout << "report mismatch2" << endl;
        return -1;
        //never merge reports
    }
    // never merge two reports
    // NOTE: this is *not* the behavior of the micron compiler TODO
    else if(isReporting() || other->isReporting()){
        if(debug_out)
            cout << "report mismatch3" << endl;
        return -1;
    }

    // check input sizes
    if(inputs.size() != other->getInputs().size()) {

        //can merge start states that self reference
        if(inputs.size() > other->getInputs().size()){
        if(debug_out)
            cout << "input size mismatch1" << endl;
            return 1;
        } else {
        if(debug_out)
            cout << "input size mismatch2" << endl;
            return -1;
        }
    }

    // for each input key, check if output has it;
    // if it doesn't, just say we are greater;
    // disregard self references because these are safe
    // TODO:: this seems very inefficient but isn't too slow in practice

    vector<string> keys;
    vector<string> other_keys;

    bool input_check = false;
    for(auto e : inputs) {
        if(e.first.compare(getId()) != 0){ // filter self loop
            keys.push_back(e.first);
        }
    }
    sort(keys.begin(), keys.end());

    for(auto e : other->getInputs()) {
        if(e.first.compare(other->getId()) != 0) { // filter self loop
            other_keys.push_back(e.first);
        }
    }
    sort(other_keys.begin(), other_keys.end());

    // check input sizes again
    if(keys.size() != other_keys.size()) {
        if(debug_out)
        cout << "inputs don't match" << endl;
        if(keys.size() > other_keys.size())
            return 1;
        else
            return -1;
    }

    // compare sorted input keys, returning lexocographic ordering of first mismatch
    /*if(debug_out){
        for(int i = 0; i < keys.size(); i++){
    	    cout << keys[i] << "asf" << endl;
            cout << other_keys[i] << endl;
        }
    }
*/
    for(int i = 0; i < keys.size(); i++){
	if(debug_out)
	cout<< keys[i] << " " << other_keys[i]<<endl;
        int comp_result = keys[i].compare(other_keys[i]);
        if(comp_result > 0){
            if(debug_out){
                cout << "inputs don't match2" << endl;
            }
            return 1;

        }else if(comp_result < 0) {
        if(debug_out)
            cout << "inputs don't match3" << endl;
            return -1;
        }
    }

    // match returns 0
    /*
    cout << "*************" << endl;
    cout << toString() << "\n" << other->toString();
    cout << "*************" << endl;
    */
    /*
    if(symbol_set.compare(other->getSymbolSet()) != 0){
        cout << "MISMATCH" << endl;
        cout << "*************" << endl;
        cout << toString() << "\n" << other->toString();
        for(int i = 0; i < 256; i++){
            cout << bit_column.test(i) << endl;
        }
        cout << "*************" << endl;

    }
    */

    return 0;
}

/**
 * Implements compare for STE columns (greater than)
 */
int STE::compareSymbolSet(STE *other) {

    // check bit vector
    //bool * other_column = other->getBitColumn();
    bitset<256> other_column = other->getBitColumn();
    for(int i = 0; i < 256; i++) {
        // if we find a true before we find a true in the other column, return true
        if(bit_column[i] == true && other_column[i] == false) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return 1;
        }else if(bit_column[i] == false && other_column[i] == true) {
            //cout << "charset greater: " << getSymbolSet() << " :: " << other->getSymbolSet() << endl;
            return -1;
        }
   }

    return 0;
}

/**
 *
 */
STE *STE::clone() {

    STE * clone = new STE(getId(), getSymbolSet(), getStringStart());

    if(isReporting()){
        clone->setReporting(true);
        clone->setReportCode(getReportCode());
    }

    // id's are the same, but we don't want that
    // append unique int id to string id;
    string new_id = clone->getId() +"_" + to_string(clone->getIntId());
    clone->setId(new_id);

    /*
    // add all inputs
    for(auto in : inputs){
        clone->addInput(in.first);
    }

    // add all outputs
    for(auto out : getOutputSTEPointers()){
        clone->addOutput(out.second);
        clone->addOutputPointer(out.first, out.second);
    }
    */

    return clone;
}

/**
 *
 */
void STE::follow(uint32_t character, set<STE*> *follow_set){

    for(auto e : outputSTEPointers){

        STE *s = static_cast<STE*>(e.first);
        if(s->match(character))
            follow_set->insert(s);
    }
}

/**
 *
 */
ElementType STE::getType() {

    return ElementType::STE_T;
}

/**
 * Replaces illegal XML chars in charset with hex version
 */
void STE::sanitizeSymbolSet() {

    // &
    size_t loc = symbol_set.find("&");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x26").length(), "\\x26");
        loc = symbol_set.find("&");
    }

    // <
    loc = symbol_set.find("<");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x3C").length(), "\\x3C");
        loc = symbol_set.find("<");
    }

    // <
    loc = symbol_set.find(">");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x3E").length(), "\\x3E");
        loc = symbol_set.find(">");
    }

    // "
    loc = symbol_set.find("\"");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x22").length(), "\\x22");
        loc = symbol_set.find("\"");
    }

    // '
    loc = symbol_set.find("\'");
    while(loc != string::npos) {
        symbol_set.replace(loc, string("\\x27").length(), "\\x27");
        loc = symbol_set.find("\'");
    }
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by FThauer FHammer   *
 *   f.thauer@web.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#define NOMINMAX // for Windows

#include "tools.h"
#include <core/loghelper.h>
#include <core/openssl_wrapper.h>

#include <boost/thread.hpp>
#include <boost/nondet_random.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <set>
#include <limits>

using namespace std;

#if 0 // TODO temporarily disabled until build problems are solved
boost::thread_specific_ptr<boost::random_device> g_rand_state;

struct nondet_rng : std::unary_function<unsigned, unsigned> {
	boost::random_device &_state;
	unsigned operator()(unsigned i) {
		boost::uniform_int<> rng(0, i - 1);
		return rng(_state);
	}
	nondet_rng(boost::random_device &state) : _state(state) {}
};

static inline void InitRandState() {
	if (!g_rand_state.get()) {
		g_rand_state.reset(new boost::random_device);
	}
}

void Tools::ShuffleArrayNonDeterministic(int *inout, unsigned count)
{
	InitRandState();
	nondet_rng rand(*g_rand_state);
	std::random_shuffle(&inout[0], &inout[count], rand);
}

void Tools::GetRand(int minValue, int maxValue, unsigned count, int *out)
{
	InitRandState();
	boost::uniform_int<> dist(minValue, maxValue);
	boost::variate_generator<boost::random_device&, boost::uniform_int<> > gen(*g_rand_state, dist);
	int *startPtr = out;
	for (unsigned i = 0; i < count; i++) {
			*startPtr++ = gen();
	}
}

void Tools::GetRandUnique(int minValue, int maxValue, unsigned count, int *out)
{
	InitRandState();
	unsigned numCreated = 0;
	int *startPtr = out;
	std::set<int> tmpSet;
	for (unsigned i = 0; i < count; i++) {
			boost::uniform_int<> dist(minValue, maxValue - numCreated);
			boost::variate_generator<boost::random_device&, boost::uniform_int<> > gen(*g_rand_state, dist);
			*startPtr = gen();
			std::set<int>::const_iterator v = tmpSet.begin();
			std::set<int>::const_iterator end = tmpSet.end();
			while (v != end) {
					if (*v <= *startPtr) {
							(*startPtr)++;
					}
					++v;
			}
			tmpSet.insert(*startPtr);
			startPtr++;
			numCreated++;
	}
}
#endif

void Tools::getRandNumber(int start, int end, int howMany, int* randArray, bool different, int* bad, int countBad)
{

	int r = end-start+1;
	unsigned char rand_buf[4];
	unsigned int randNumber;

	int i;

	if (!different) {

		int counter(0);
		while(counter < howMany) {

			if(!RAND_bytes(rand_buf, 4)) {
				LOG_MSG("RAND_bytes failed!");
			}

			randNumber = 0;
			for(i=0; i<4; i++) {
				randNumber += (rand_buf[i] << 8*i);
			}

			if(randNumber < ( (unsigned int) ( ((double)numeric_limits<unsigned int>::max()) / r ) ) * r) {
				randArray[counter] = start + (randNumber % r);
				counter++;
			}

		}
	} else {

		int *tempArray = new int[end-start+1];
		for (i=0; i<(end-start+1); i++) tempArray[i]=1;

		if(bad) {
			for(i=0; i<countBad; i++) {
				tempArray[bad[i]]=0;
			}
		}

		int counter(0);
		while (counter < howMany) {

			if(!RAND_bytes(rand_buf, 4)) {
				LOG_MSG("RAND_bytes failed!");
			}

			randNumber = 0;
			for(i=0; i<4; i++) {
				randNumber += (rand_buf[i] << 8*i);
			}

			if(randNumber < ( (unsigned int) ( ((double)numeric_limits<unsigned int>::max()) / r ) ) * r) {
				randNumber = randNumber % r;

				if (tempArray[randNumber] == 1) {

					randArray[counter] = start + randNumber;
					tempArray[randNumber] = 0;
					counter++;
				}
			}

		}

		delete[] tempArray;
	}

}

<commit_msg>Cosmetic changes.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by FThauer FHammer   *
 *   f.thauer@web.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#define NOMINMAX // for Windows

#include "tools.h"
#include <core/loghelper.h>
#include <core/openssl_wrapper.h>

#include <boost/thread.hpp>
#include <boost/nondet_random.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <set>
#include <limits>

using namespace std;

#if 0 // TODO temporarily disabled until build problems are solved
boost::thread_specific_ptr<boost::random_device> g_rand_state;

struct nondet_rng : std::unary_function<unsigned, unsigned> {
	boost::random_device &_state;
	unsigned operator()(unsigned i) {
		boost::uniform_int<> rng(0, i - 1);
		return rng(_state);
	}
	nondet_rng(boost::random_device &state) : _state(state) {}
};

static inline void InitRandState()
{
	if (!g_rand_state.get()) {
		g_rand_state.reset(new boost::random_device);
	}
}

void Tools::ShuffleArrayNonDeterministic(int *inout, unsigned count)
{
	InitRandState();
	nondet_rng rand(*g_rand_state);
	random_shuffle(&inout[0], &inout[count], rand);
}

void Tools::GetRand(int minValue, int maxValue, unsigned count, int *out)
{
	InitRandState();
	boost::uniform_int<> dist(minValue, maxValue);
	boost::variate_generator<boost::random_device&, boost::uniform_int<> > gen(*g_rand_state, dist);
	int *startPtr = out;
	for (unsigned i = 0; i < count; i++) {
		*startPtr++ = gen();
	}
}

void Tools::GetRandUnique(int minValue, int maxValue, unsigned count, int *out)
{
	InitRandState();
	unsigned numCreated = 0;
	int *startPtr = out;
	set<int> tmpSet;
	for (unsigned i = 0; i < count; i++) {
		boost::uniform_int<> dist(minValue, maxValue - numCreated);
		boost::variate_generator<boost::random_device&, boost::uniform_int<> > gen(*g_rand_state, dist);
		*startPtr = gen();
		set<int>::const_iterator v = tmpSet.begin();
		set<int>::const_iterator end = tmpSet.end();
		while (v != end) {
			if (*v <= *startPtr) {
				(*startPtr)++;
			}
			++v;
		}
		tmpSet.insert(*startPtr);
		startPtr++;
		numCreated++;
	}
}
#endif

void Tools::getRandNumber(int start, int end, int howMany, int* randArray, bool different, int* bad, int countBad)
{

	int r = end-start+1;
	unsigned char rand_buf[4];
	unsigned int randNumber;

	int i;

	if (!different) {

		int counter(0);
		while(counter < howMany) {

			if(!RAND_bytes(rand_buf, 4)) {
				LOG_MSG("RAND_bytes failed!");
			}

			randNumber = 0;
			for(i=0; i<4; i++) {
				randNumber += (rand_buf[i] << 8*i);
			}

			if(randNumber < ( (unsigned int) ( ((double)numeric_limits<unsigned int>::max()) / r ) ) * r) {
				randArray[counter] = start + (randNumber % r);
				counter++;
			}

		}
	} else {

		int *tempArray = new int[end-start+1];
		for (i=0; i<(end-start+1); i++) tempArray[i]=1;

		if(bad) {
			for(i=0; i<countBad; i++) {
				tempArray[bad[i]]=0;
			}
		}

		int counter(0);
		while (counter < howMany) {

			if(!RAND_bytes(rand_buf, 4)) {
				LOG_MSG("RAND_bytes failed!");
			}

			randNumber = 0;
			for(i=0; i<4; i++) {
				randNumber += (rand_buf[i] << 8*i);
			}

			if(randNumber < ( (unsigned int) ( ((double)numeric_limits<unsigned int>::max()) / r ) ) * r) {
				randNumber = randNumber % r;

				if (tempArray[randNumber] == 1) {

					randArray[counter] = start + randNumber;
					tempArray[randNumber] = 0;
					counter++;
				}
			}

		}

		delete[] tempArray;
	}

}

<|endoftext|>


<commit_before>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have
/// all completed. For example, can be used to ensure that all tasks of a parallel loop have
/// completed, including tasks or asynchronous delegates spawned during execution of the
/// parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest
/// way is to declare it as file-global or static storage). TODO: allow dynamic allocation
/// in Grappa linear address space.
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block.
/// When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be
/// causally followed by "complete", so either must be completed from the same task that
/// called "enroll" or from a task spawned (transitively) from the enrolling task.
///
/// This is meant to be a reusable barrier; GCE's should begin in a state where a call to
/// `wait` will fall through, and end up, after all tasks are completed, back in the same
/// state. Note: `reset` no longer needs to be called between phases. Instead, it just
/// must be guaranteed that at least one task has been enrolled before anyone tries to
/// call `wait` otherwise they may fall through before the enrollment has completed.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// This is the state the GCE's on each core should be in at the beginning, and the
  /// state they should end up in after a Completion phase. I should no longer be necessary
  /// to call `reset` between calls to `wait` as long as nothing fishy is going on.
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler.
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      VLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  /// Suspend calling task until all tasks completed (including additional tasks enrolled
  /// before count goes to 0). This can be called from as many tasks as desired on
  /// different cores, as long as it is ensured that a task in the desired phase has been
  /// enrolled before wait is called.
  ///
  /// If no tasks have been enrolled, or all have been completed by the time `wait` is called,
  /// this will fall through and not suspend the calling task.
  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        VLOG(3) << "woke from conservative check";
      }
      VLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  /// In this version, GCE is a template parameter to avoid taking up space in the task's args.
  template<GlobalCompletionEvent * GCE, typename TF>
  void privateTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    privateTask([tf] {
      tf();
      if (GCE) GCE->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }

} // namespace Grappa
<commit_msg>Make some output Debug only.<commit_after>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have
/// all completed. For example, can be used to ensure that all tasks of a parallel loop have
/// completed, including tasks or asynchronous delegates spawned during execution of the
/// parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest
/// way is to declare it as file-global or static storage). TODO: allow dynamic allocation
/// in Grappa linear address space.
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block.
/// When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be
/// causally followed by "complete", so either must be completed from the same task that
/// called "enroll" or from a task spawned (transitively) from the enrolling task.
///
/// This is meant to be a reusable barrier; GCE's should begin in a state where a call to
/// `wait` will fall through, and end up, after all tasks are completed, back in the same
/// state. Note: `reset` no longer needs to be called between phases. Instead, it just
/// must be guaranteed that at least one task has been enrolled before anyone tries to
/// call `wait` otherwise they may fall through before the enrollment has completed.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// This is the state the GCE's on each core should be in at the beginning, and the
  /// state they should end up in after a Completion phase. I should no longer be necessary
  /// to call `reset` between calls to `wait` as long as nothing fishy is going on.
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler.
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      DVLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  /// Suspend calling task until all tasks completed (including additional tasks enrolled
  /// before count goes to 0). This can be called from as many tasks as desired on
  /// different cores, as long as it is ensured that a task in the desired phase has been
  /// enrolled before wait is called.
  ///
  /// If no tasks have been enrolled, or all have been completed by the time `wait` is called,
  /// this will fall through and not suspend the calling task.
  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        DVLOG(3) << "woke from conservative check";
      }
      DVLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  /// In this version, GCE is a template parameter to avoid taking up space in the task's args.
  template<GlobalCompletionEvent * GCE, typename TF>
  void privateTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    privateTask([tf] {
      tf();
      if (GCE) GCE->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }

} // namespace Grappa
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_PLUS_HPP
#define STAN_MATH_PRIM_FUN_PLUS_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
 * Returns the unary plus of the input.
 *
 * @tparam T Type of input.
 * @param x input.
 * @return result of unary plus of the input.
 */
template <typename T>
inline plain_type_t<T> plus(const T& x) {
  return x;
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>rework plus() for perfect forwarding<commit_after>#ifndef STAN_MATH_PRIM_FUN_PLUS_HPP
#define STAN_MATH_PRIM_FUN_PLUS_HPP

#include <stan/math/prim/meta.hpp>

namespace stan {
namespace math {

/**
 * Returns the unary plus of the input.
 *
 * @tparam T Type of input.
 * @param x input.
 * @return result of unary plus of the input.
 */
template <typename T>
inline T plus(T&& x) {
  return std::forward(x);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"

static const char * progress_prompt;
static uint64_t progress_next;
static uint64_t progress_size;
static uint64_t progress_chunk;
const size_t memalignment = 16;

void progress_init(const char * prompt, uint64_t size)
{
  constexpr uint64_t progress_granularity {200};
  progress_prompt = prompt;
  progress_size = size;
  progress_chunk = size < progress_granularity ?
    1 : size / progress_granularity;
  progress_next = 1;
  if (! opt_log.empty()) {
    fprintf(logfile, "%s", prompt);
  }
  else {
    fprintf(logfile, "%s %.0f%%", prompt, 0.0);
  }
}

void progress_update(uint64_t progress)
{
  if (opt_log.empty() && (progress >= progress_next))
    {
      fprintf(logfile, "  \r%s %.0f%%", progress_prompt,
              100.0 * static_cast<double>(progress)
              / static_cast<double>(progress_size));
      progress_next = progress + progress_chunk;
      fflush(logfile);
    }
}

void progress_done()
{
  if (! opt_log.empty()) {
    fprintf(logfile, " %.0f%%\n", 100.0);
  }
  else {
    fprintf(logfile, "  \r%s %.0f%%\n", progress_prompt, 100.0);
  }
  fflush(logfile);
}

// std::gcd() in C++17
auto gcd(int64_t a, int64_t b) -> int64_t
{
  return b == 0 ? a : gcd(b, a % b);
}

[[ noreturn ]] void fatal(const char * msg)
{
  fprintf(stderr, "\nError: %s\n", msg);
  exit(1);
}

auto xmalloc(size_t size) -> void *
{
  if (size == 0) {
    size = 1;
  }
  void * t {nullptr};
#ifdef _WIN32
  t = _aligned_malloc(size, memalignment);
#else
  if (posix_memalign(& t, memalignment, size) != 0) {
    t = nullptr;
  }
#endif
  if (t == nullptr) {
    fatal("Unable to allocate enough memory.");
  }
  return t;
}

auto xrealloc(void *ptr, size_t size) -> void *
{
  if (size == 0) {
    size = 1;
  }
#ifdef _WIN32
  void * t = _aligned_realloc(ptr, size, memalignment);
#else
  void * t = realloc(ptr, size);
#endif
  if (t == nullptr) {
    fatal("Unable to reallocate enough memory.");
  }
  return t;
}

void xfree(void * ptr)
{
  if (ptr != nullptr)
    {
#ifdef _WIN32
      _aligned_free(ptr);
#else
      free(ptr);
#endif
    }
  else {
    fatal("Trying to free a null pointer");
  }
}

auto fopen_input(const char * filename) -> std::FILE *
{
  /* open the input stream given by filename, but use stdin if name is - */
  std::FILE * input_stream = nullptr;

  if (strcmp(filename, "-") == 0) {
    int fd = dup(STDIN_FILENO);
    input_stream = fd > 0 ? fdopen(fd, "rb") : nullptr;
  }
  else {
    input_stream = fopen(filename, "rb");
  }

  return input_stream;
}

auto fopen_output(const char * filename) -> std::FILE *
{
  /* open the output stream given by filename, but use stdout if name is - */
  std::FILE * output_stream {nullptr};

  if (strcmp(filename, "-") == 0) {
    int fd = dup(STDOUT_FILENO);
    output_stream = fd > 0 ? fdopen(fd, "w") : nullptr;
  }
  else {
    output_stream = fopen(filename, "w");
  }

  return output_stream;
}

auto xgetline(char ** linep, size_t * linecapp, FILE * stream) -> ssize_t
{
#ifndef _WIN32

  return getline(linep, linecapp, stream);

#else

  /*
     Replacement for the getline function.
     May be used on Windows and other non-POSIX systems.
     Dynamic buffer expansion while reading input using fgets.
     Considerably slower since it calls getc repeatedly.

     Using fgets is much faster but does not work properly as
     it cannot handle NUL characters in the string correctly.
     Important for correct counting of characters and file size.
  */

  const size_t minsize = 2;
  const size_t maxsize = SIZE_MAX / 2;

  /* Error if linep or linecapp pointers are null */
  if ((linep == nullptr) || (linecapp == nullptr))
    {
      errno = EINVAL;
      return -1;
    }

  if (*linep == nullptr)
    {
      /* allocate a default buffer if linep is a null pointer */
      *linecapp = minsize;
      *linep = (char *) malloc(*linecapp);
      if (*linep == nullptr)
        return -1;
    }

  char * p = *linep;            // pointer to where to put next char
  char * e = p + *linecapp - 1; // pointer to last byte in buffer
  size_t len = 0;
  *p = 0;

  while (1)
    {
      while (p < e)
        {
          int c = getc(stream);
          switch(c)
            {
            case -1:
              if (feof(stream))
                {
                  // EOF, add NUL
                  *p = 0;
                  len = p - *linep;
                  if (len > 0)
                    return len;
                  else
                    return -1;
                }
              else
                {
                  // Error
                  return -1;
                }

            case '\n':
              // Newline
              *p++ = c;
              *p = 0;
              return p - *linep;

            default:
              // Ordinary character, including NUL
              *p++ = c;
              break;
            }
        }

      // Increase buffer size

      if (*linecapp >= maxsize)
        {
          errno = EOVERFLOW;
          return -1;
        }

      size_t newlinecap = minsize;
      while ((newlinecap <= *linecapp) && (newlinecap < maxsize))
        newlinecap *= 2;

      if (newlinecap > maxsize)
        {
          errno = EOVERFLOW;
          return -1;
        }

      char * newlinep = (char *) realloc(*linep, newlinecap);
      if (newlinep == nullptr)
        {
          // Memory allocation error
          return -1;
        }

      len = p - *linep;
      *linep = newlinep;
      *linecapp = newlinecap;
      p = newlinep + len;
      e = p + *linecapp - 1;
    }
#endif
}
<commit_msg>More accurate description of xgetline<commit_after>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"

static const char * progress_prompt;
static uint64_t progress_next;
static uint64_t progress_size;
static uint64_t progress_chunk;
const size_t memalignment = 16;

void progress_init(const char * prompt, uint64_t size)
{
  constexpr uint64_t progress_granularity {200};
  progress_prompt = prompt;
  progress_size = size;
  progress_chunk = size < progress_granularity ?
    1 : size / progress_granularity;
  progress_next = 1;
  if (! opt_log.empty()) {
    fprintf(logfile, "%s", prompt);
  }
  else {
    fprintf(logfile, "%s %.0f%%", prompt, 0.0);
  }
}

void progress_update(uint64_t progress)
{
  if (opt_log.empty() && (progress >= progress_next))
    {
      fprintf(logfile, "  \r%s %.0f%%", progress_prompt,
              100.0 * static_cast<double>(progress)
              / static_cast<double>(progress_size));
      progress_next = progress + progress_chunk;
      fflush(logfile);
    }
}

void progress_done()
{
  if (! opt_log.empty()) {
    fprintf(logfile, " %.0f%%\n", 100.0);
  }
  else {
    fprintf(logfile, "  \r%s %.0f%%\n", progress_prompt, 100.0);
  }
  fflush(logfile);
}

// std::gcd() in C++17
auto gcd(int64_t a, int64_t b) -> int64_t
{
  return b == 0 ? a : gcd(b, a % b);
}

[[ noreturn ]] void fatal(const char * msg)
{
  fprintf(stderr, "\nError: %s\n", msg);
  exit(1);
}

auto xmalloc(size_t size) -> void *
{
  if (size == 0) {
    size = 1;
  }
  void * t {nullptr};
#ifdef _WIN32
  t = _aligned_malloc(size, memalignment);
#else
  if (posix_memalign(& t, memalignment, size) != 0) {
    t = nullptr;
  }
#endif
  if (t == nullptr) {
    fatal("Unable to allocate enough memory.");
  }
  return t;
}

auto xrealloc(void *ptr, size_t size) -> void *
{
  if (size == 0) {
    size = 1;
  }
#ifdef _WIN32
  void * t = _aligned_realloc(ptr, size, memalignment);
#else
  void * t = realloc(ptr, size);
#endif
  if (t == nullptr) {
    fatal("Unable to reallocate enough memory.");
  }
  return t;
}

void xfree(void * ptr)
{
  if (ptr != nullptr)
    {
#ifdef _WIN32
      _aligned_free(ptr);
#else
      free(ptr);
#endif
    }
  else {
    fatal("Trying to free a null pointer");
  }
}

auto fopen_input(const char * filename) -> std::FILE *
{
  /* open the input stream given by filename, but use stdin if name is - */
  std::FILE * input_stream = nullptr;

  if (strcmp(filename, "-") == 0) {
    int fd = dup(STDIN_FILENO);
    input_stream = fd > 0 ? fdopen(fd, "rb") : nullptr;
  }
  else {
    input_stream = fopen(filename, "rb");
  }

  return input_stream;
}

auto fopen_output(const char * filename) -> std::FILE *
{
  /* open the output stream given by filename, but use stdout if name is - */
  std::FILE * output_stream {nullptr};

  if (strcmp(filename, "-") == 0) {
    int fd = dup(STDOUT_FILENO);
    output_stream = fd > 0 ? fdopen(fd, "w") : nullptr;
  }
  else {
    output_stream = fopen(filename, "w");
  }

  return output_stream;
}

auto xgetline(char ** linep, size_t * linecapp, FILE * stream) -> ssize_t
{
#ifndef _WIN32

  return getline(linep, linecapp, stream);

#else

  /*
     Replacement for the POSIX getline function.
     May be used on Windows and other non-POSIX systems.
     Dynamic buffer expansion while reading input.
     Considerably slower since it calls getc repeatedly.

     Using fgets is much faster but does not work properly as
     it cannot handle NUL characters in the string correctly,
     which is important for correct counting of characters and file size.
  */

  const size_t minsize = 2;
  const size_t maxsize = SIZE_MAX / 2;

  /* Error if linep or linecapp pointers are null */
  if ((linep == nullptr) || (linecapp == nullptr))
    {
      errno = EINVAL;
      return -1;
    }

  if (*linep == nullptr)
    {
      /* allocate a default buffer if linep is a null pointer */
      *linecapp = minsize;
      *linep = (char *) malloc(*linecapp);
      if (*linep == nullptr)
        return -1;
    }

  char * p = *linep;            // pointer to where to put next char
  char * e = p + *linecapp - 1; // pointer to last byte in buffer
  size_t len = 0;
  *p = 0;

  while (1)
    {
      while (p < e)
        {
          int c = getc(stream);
          switch(c)
            {
            case -1:
              if (feof(stream))
                {
                  // EOF, add NUL
                  *p = 0;
                  len = p - *linep;
                  if (len > 0)
                    return len;
                  else
                    return -1;
                }
              else
                {
                  // Error
                  return -1;
                }

            case '\n':
              // Newline
              *p++ = c;
              *p = 0;
              return p - *linep;

            default:
              // Ordinary character, including NUL
              *p++ = c;
              break;
            }
        }

      // Increase buffer size

      if (*linecapp >= maxsize)
        {
          errno = EOVERFLOW;
          return -1;
        }

      size_t newlinecap = minsize;
      while ((newlinecap <= *linecapp) && (newlinecap < maxsize))
        newlinecap *= 2;

      if (newlinecap > maxsize)
        {
          errno = EOVERFLOW;
          return -1;
        }

      char * newlinep = (char *) realloc(*linep, newlinecap);
      if (newlinep == nullptr)
        {
          // Memory allocation error
          return -1;
        }

      len = p - *linep;
      *linep = newlinep;
      *linecapp = newlinecap;
      p = newlinep + len;
      e = p + *linecapp - 1;
    }
#endif
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_shelf.h"

#include "base/logging.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_service.h"
#include "skia/ext/skia_utils.h"

namespace {

// Margins around the content.
static const int kTopMargin = 1;
static const int kBottomMargin = 2;
static const int kLeftMargin = 1;
static const int kRightMargin = 1;

// Padding between extension toolstrips.
static const int kToolstripPadding = 2;

// Preferred height of the ExtensionShelf.
static const int kShelfHeight = 29;

// Colors for the ExtensionShelf.
static const SkColor kBackgroundColor = SkColorSetRGB(230, 237, 244);
static const SkColor kBorderColor = SkColorSetRGB(201, 212, 225);
static const SkColor kSeparatorHighlightColor = SkColorSetRGB(247, 250, 253);

// TODO(erikkay) convert back to a gradient when Glen figures out the
// specs.
// static const SkColor kBackgroundColor = SkColorSetRGB(237, 244, 252);
// static const SkColor kTopGradientColor = SkColorSetRGB(222, 234, 248);

}  // namespace

ExtensionShelf::ExtensionShelf(Browser* browser) : browser_(browser) {
  // Watch extensions loaded notification.
  NotificationService* ns = NotificationService::current();
  Source<Profile> ns_source(browser->profile()->GetOriginalProfile());
  ns->AddObserver(this, NotificationType::EXTENSIONS_LOADED,
                  NotificationService::AllSources());

  // Add any already-loaded extensions now, since we missed the notification for
  // those.
  ExtensionsService* service = browser_->profile()->GetExtensionsService();
  if (service) {  // This can be null in unit tests.
    if (AddExtensionViews(service->extensions())) {
      Layout();
      SchedulePaint();
    }
  }
}

ExtensionShelf::~ExtensionShelf() {
  NotificationService* ns = NotificationService::current();
  ns->RemoveObserver(this, NotificationType::EXTENSIONS_LOADED,
                     NotificationService::AllSources());
}

void ExtensionShelf::Paint(ChromeCanvas* canvas) {
#if 0
  // TODO(erikkay) re-enable this when Glen has the gradient values worked out.
  SkPaint paint;
  paint.setShader(skia::CreateGradientShader(0,
                                             height(),
                                             kTopGradientColor,
                                             kBackgroundColor))->safeUnref();
  canvas->FillRectInt(0, 0, width(), height(), paint);
#else
  canvas->FillRectInt(kBackgroundColor, 0, 0, width(), height());
#endif

  canvas->FillRectInt(kBorderColor, 0, 0, width(), 1);
  canvas->FillRectInt(kBorderColor, 0, height() - 1, width(), 1);

  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i) {
    int right = GetChildViewAt(i)->bounds().right();
    int h = height() - 2;
    canvas->FillRectInt(kBorderColor, right, 1, 1, h);
    canvas->FillRectInt(kSeparatorHighlightColor, right + 1, 1, 1, h);
  }

  SkRect background_rect = {
      SkIntToScalar(0),
      SkIntToScalar(1),
      SkIntToScalar(1),
      SkIntToScalar(height() - 2)};
  InitBackground(canvas, background_rect);
}

gfx::Size ExtensionShelf::GetPreferredSize() {
  if (HasExtensionViews())
    return gfx::Size(0, kShelfHeight);
  return gfx::Size(0, 0);
}

void ExtensionShelf::Layout() {
  if (!GetParent())
    return;

  int x = kLeftMargin;
  int y = kTopMargin;
  int content_height = height() - kTopMargin - kBottomMargin;
  int max_x = width() - kRightMargin;

  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i) {
    views::View* child = GetChildViewAt(i);
    gfx::Size pref = child->GetPreferredSize();
    int next_x = x + pref.width() + kToolstripPadding;
    child->SetVisible(next_x < max_x);
    child->SetBounds(x, y, pref.width(), content_height);
    child->Layout();
    x = next_x;
  }
}

void ExtensionShelf::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_LOADED: {
      const ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      if (AddExtensionViews(extensions)) {
        Layout();
        SchedulePaint();
        // TODO(erikkay) come up with a better way to notify parents
        if (GetParent())
          GetParent()->Layout();
      }
      break;
    }
    default:
      DCHECK(false) << "Unhandled notification of type: " << type.value;
      break;
  }
}

bool ExtensionShelf::AddExtensionViews(const ExtensionList* extensions) {
  bool added_toolstrip = false;
  ExtensionsService* service = browser_->profile()->GetExtensionsService();
  for (ExtensionList::const_iterator extension = extensions->begin();
       extension != extensions->end(); ++extension) {
    for (std::vector<std::string>::const_iterator toolstrip_path =
         (*extension)->toolstrips().begin();
         toolstrip_path != (*extension)->toolstrips().end(); ++toolstrip_path) {
      ExtensionView* toolstrip =
          service->CreateView(*extension,
                              (*extension)->GetResourceURL(*toolstrip_path),
                              browser_);
      if (!background_.empty())
        toolstrip->SetBackground(background_);
      AddChildView(toolstrip);
      added_toolstrip = true;
    }
  }
  return added_toolstrip;
}

bool ExtensionShelf::HasExtensionViews() {
  return GetChildViewCount() > 0;
}

void ExtensionShelf::InitBackground(ChromeCanvas* canvas,
                                    const SkRect& subset) {
  if (!background_.empty())
    return;

  const SkBitmap& background = canvas->getDevice()->accessBitmap(false);

  // Extract the correct subset of the toolstrip background into a bitmap. We
  // must use a temporary here because extractSubset() returns a bitmap that
  // references pixels in the original one and we want to actually make a copy
  // that will have a long lifetime.
  SkBitmap temp;
  temp.setConfig(background.config(),
                 static_cast<int>(subset.width()),
                 static_cast<int>(subset.height()));

  SkRect mapped_subset = subset;
  bool result = canvas->getTotalMatrix().mapRect(&mapped_subset);
  DCHECK(result);

  SkIRect isubset;
  mapped_subset.round(&isubset);
  result = background.extractSubset(&temp, isubset);
  if (!result)
    return;

  temp.copyTo(&background_, temp.config());
  DCHECK(background_.readyToDraw());

  // Tell all extension views about the new background
  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i)
    static_cast<ExtensionView*>(GetChildViewAt(i))->SetBackground(background_);
}
<commit_msg>Tweak the padding around toolstrips on the extension shelf.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_shelf.h"

#include "base/logging.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension.h"
#include "chrome/browser/extensions/extension_view.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_service.h"
#include "skia/ext/skia_utils.h"

namespace {

// Margins around the content.
static const int kTopMargin = 2;
static const int kBottomMargin = 2;
static const int kLeftMargin = 0;
static const int kRightMargin = 0;

// Padding on left and right side of an extension toolstrip.
static const int kToolstripPadding = 2;

// Width of the toolstrip divider.
static const int kToolstripDividerWidth = 2;

// Preferred height of the ExtensionShelf.
static const int kShelfHeight = 29;

// Colors for the ExtensionShelf.
static const SkColor kBackgroundColor = SkColorSetRGB(230, 237, 244);
static const SkColor kBorderColor = SkColorSetRGB(201, 212, 225);
static const SkColor kDividerHighlightColor = SkColorSetRGB(247, 250, 253);

// TODO(erikkay) convert back to a gradient when Glen figures out the
// specs.
// static const SkColor kBackgroundColor = SkColorSetRGB(237, 244, 252);
// static const SkColor kTopGradientColor = SkColorSetRGB(222, 234, 248);

}  // namespace

ExtensionShelf::ExtensionShelf(Browser* browser) : browser_(browser) {
  // Watch extensions loaded notification.
  NotificationService* ns = NotificationService::current();
  Source<Profile> ns_source(browser->profile()->GetOriginalProfile());
  ns->AddObserver(this, NotificationType::EXTENSIONS_LOADED,
                  NotificationService::AllSources());

  // Add any already-loaded extensions now, since we missed the notification for
  // those.
  ExtensionsService* service = browser_->profile()->GetExtensionsService();
  if (service) {  // This can be null in unit tests.
    if (AddExtensionViews(service->extensions())) {
      Layout();
      SchedulePaint();
    }
  }
}

ExtensionShelf::~ExtensionShelf() {
  NotificationService* ns = NotificationService::current();
  ns->RemoveObserver(this, NotificationType::EXTENSIONS_LOADED,
                     NotificationService::AllSources());
}

void ExtensionShelf::Paint(ChromeCanvas* canvas) {
#if 0
  // TODO(erikkay) re-enable this when Glen has the gradient values worked out.
  SkPaint paint;
  paint.setShader(skia::CreateGradientShader(0,
                                             height(),
                                             kTopGradientColor,
                                             kBackgroundColor))->safeUnref();
  canvas->FillRectInt(0, 0, width(), height(), paint);
#else
  canvas->FillRectInt(kBackgroundColor, 0, 0, width(), height());
#endif

  canvas->FillRectInt(kBorderColor, 0, 0, width(), 1);
  canvas->FillRectInt(kBorderColor, 0, height() - 1, width(), 1);

  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i) {
    int right = GetChildViewAt(i)->bounds().right() + kToolstripPadding;
    int h = height() - 2;
    canvas->FillRectInt(kBorderColor, right, 1, 1, h);
    canvas->FillRectInt(kDividerHighlightColor, right + 1, 1, 1, h);
  }

  SkRect background_rect = {
      SkIntToScalar(0),
      SkIntToScalar(1),
      SkIntToScalar(1),
      SkIntToScalar(height() - 2)};
  InitBackground(canvas, background_rect);
}

gfx::Size ExtensionShelf::GetPreferredSize() {
  if (HasExtensionViews())
    return gfx::Size(0, kShelfHeight);
  return gfx::Size(0, 0);
}

void ExtensionShelf::Layout() {
  if (!GetParent())
    return;

  int x = kLeftMargin;
  int y = kTopMargin;
  int content_height = height() - kTopMargin - kBottomMargin;
  int max_x = width() - kRightMargin;

  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i) {
    x += kToolstripPadding;  // left padding
    views::View* child = GetChildViewAt(i);
    gfx::Size pref = child->GetPreferredSize();
    int next_x = x + pref.width() + kToolstripPadding;  // right padding
    child->SetVisible(next_x < max_x);
    child->SetBounds(x, y, pref.width(), content_height);
    child->Layout();
    x = next_x + kToolstripDividerWidth;
  }
}

void ExtensionShelf::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_LOADED: {
      const ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      if (AddExtensionViews(extensions)) {
        Layout();
        SchedulePaint();
        // TODO(erikkay) come up with a better way to notify parents
        if (GetParent())
          GetParent()->Layout();
      }
      break;
    }
    default:
      DCHECK(false) << "Unhandled notification of type: " << type.value;
      break;
  }
}

bool ExtensionShelf::AddExtensionViews(const ExtensionList* extensions) {
  bool added_toolstrip = false;
  ExtensionsService* service = browser_->profile()->GetExtensionsService();
  for (ExtensionList::const_iterator extension = extensions->begin();
       extension != extensions->end(); ++extension) {
    for (std::vector<std::string>::const_iterator toolstrip_path =
         (*extension)->toolstrips().begin();
         toolstrip_path != (*extension)->toolstrips().end(); ++toolstrip_path) {
      ExtensionView* toolstrip =
          service->CreateView(*extension,
                              (*extension)->GetResourceURL(*toolstrip_path),
                              browser_);
      if (!background_.empty())
        toolstrip->SetBackground(background_);
      AddChildView(toolstrip);
      added_toolstrip = true;
    }
  }
  return added_toolstrip;
}

bool ExtensionShelf::HasExtensionViews() {
  return GetChildViewCount() > 0;
}

void ExtensionShelf::InitBackground(ChromeCanvas* canvas,
                                    const SkRect& subset) {
  if (!background_.empty())
    return;

  const SkBitmap& background = canvas->getDevice()->accessBitmap(false);

  // Extract the correct subset of the toolstrip background into a bitmap. We
  // must use a temporary here because extractSubset() returns a bitmap that
  // references pixels in the original one and we want to actually make a copy
  // that will have a long lifetime.
  SkBitmap temp;
  temp.setConfig(background.config(),
                 static_cast<int>(subset.width()),
                 static_cast<int>(subset.height()));

  SkRect mapped_subset = subset;
  bool result = canvas->getTotalMatrix().mapRect(&mapped_subset);
  DCHECK(result);

  SkIRect isubset;
  mapped_subset.round(&isubset);
  result = background.extractSubset(&temp, isubset);
  if (!result)
    return;

  temp.copyTo(&background_, temp.config());
  DCHECK(background_.readyToDraw());

  // Tell all extension views about the new background
  int count = GetChildViewCount();
  for (int i = 0; i < count; ++i)
    static_cast<ExtensionView*>(GetChildViewAt(i))->SetBackground(background_);
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/options/fonts_page_gtk.h"

#include "app/l10n_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/options/options_layout_gtk.h"
#include "chrome/common/gtk_util.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"

namespace {

// Make a Gtk font name string from a font family name and pixel size.
std::string MakeFontName(std::wstring family_name, int pixel_size) {
  std::string fontname;
  // TODO(mattm): We can pass in the size in pixels (px), and the font button
  // actually honors it, but when you open the selector it interprets it as
  // points.  See crbug.com/17857
  SStringPrintf(&fontname, "%s %dpx", WideToUTF8(family_name).c_str(),
                pixel_size);
  return fontname;
}

}  // namespace

FontsPageGtk::FontsPageGtk(Profile* profile) : OptionsPageBase(profile) {
  Init();
}

FontsPageGtk::~FontsPageGtk() {
}

void FontsPageGtk::Init() {
  OptionsLayoutBuilderGtk options_builder;

  serif_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(serif_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(serif_font_button_), TRUE);
  g_signal_connect(serif_font_button_, "font-set", G_CALLBACK(OnSerifFontSet),
                   this);

  sans_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(sans_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(sans_font_button_), TRUE);
  g_signal_connect(sans_font_button_, "font-set", G_CALLBACK(OnSansFontSet),
                   this);

  fixed_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(fixed_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(fixed_font_button_), TRUE);
  g_signal_connect(fixed_font_button_, "font-set", G_CALLBACK(OnFixedFontSet),
                   this);

  GtkWidget* font_controls = gtk_util::CreateLabeledControlsGroup(NULL,
      l10n_util::GetStringUTF8(
          IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SERIF_LABEL).c_str(),
      serif_font_button_,
      l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SANS_SERIF_LABEL).c_str(),
      sans_font_button_,
      l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_FIXED_WIDTH_LABEL).c_str(),
      fixed_font_button_,
      NULL);

  options_builder.AddOptionGroup(l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_FONT_TITLE),
      font_controls, false);

  InitDefaultEncodingComboBox();
  std::string encoding_group_description = l10n_util::GetStringUTF8(
      IDS_FONT_LANGUAGE_SETTING_FONT_DEFAULT_ENCODING_SELECTOR_LABEL);
  GtkWidget* encoding_controls = gtk_util::CreateLabeledControlsGroup(NULL,
      encoding_group_description.c_str(),
      default_encoding_combobox_,
      NULL);
  options_builder.AddOptionGroup(l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_ENCODING_TITLE),
      encoding_controls, false);

  page_ = options_builder.get_page_widget();

  serif_name_.Init(prefs::kWebKitSerifFontFamily, profile()->GetPrefs(), this);
  sans_serif_name_.Init(prefs::kWebKitSansSerifFontFamily,
                        profile()->GetPrefs(), this);
  variable_width_size_.Init(prefs::kWebKitDefaultFontSize,
                            profile()->GetPrefs(), this);

  fixed_width_name_.Init(prefs::kWebKitFixedFontFamily, profile()->GetPrefs(),
                         this);
  fixed_width_size_.Init(prefs::kWebKitDefaultFixedFontSize,
                         profile()->GetPrefs(), this);

  default_encoding_.Init(prefs::kDefaultCharset, profile()->GetPrefs(), this);

  NotifyPrefChanged(NULL);
}

void FontsPageGtk::InitDefaultEncodingComboBox() {
  default_encoding_combobox_ = gtk_combo_box_new_text();
  g_signal_connect(G_OBJECT(default_encoding_combobox_), "changed",
                   G_CALLBACK(OnDefaultEncodingChanged), this);
  int canonical_encoding_names_length =
      CharacterEncoding::GetSupportCanonicalEncodingCount();
  // Initialize the vector of all sorted encodings according to current
  // UI locale.
  std::string locale = g_browser_process->GetApplicationLocale();
  for (int i = 0; i < canonical_encoding_names_length; i++) {
    sorted_encoding_list_.push_back(CharacterEncoding::EncodingInfo(
        CharacterEncoding::GetEncodingCommandIdByIndex(i)));
  }
  l10n_util::SortVectorWithStringKey(locale, &sorted_encoding_list_, true);
  for (size_t i = 0; i < sorted_encoding_list_.size(); i++) {
    gtk_combo_box_append_text(
        GTK_COMBO_BOX(default_encoding_combobox_),
        WideToUTF8(sorted_encoding_list_[i].encoding_display_name).c_str());
  }
}

void FontsPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
  if (!pref_name || *pref_name == prefs::kWebKitSerifFontFamily ||
      *pref_name == prefs::kWebKitDefaultFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(serif_font_button_),
        MakeFontName(serif_name_.GetValue(),
          variable_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kWebKitSansSerifFontFamily ||
      *pref_name == prefs::kWebKitDefaultFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(sans_font_button_),
        MakeFontName(sans_serif_name_.GetValue(),
          variable_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kWebKitFixedFontFamily ||
      *pref_name == prefs::kWebKitDefaultFixedFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(fixed_font_button_),
        MakeFontName(fixed_width_name_.GetValue(),
          fixed_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kDefaultCharset) {
    const std::wstring current_encoding = default_encoding_.GetValue();
    for (size_t i = 0; i < sorted_encoding_list_.size(); i++) {
      if (CharacterEncoding::GetCanonicalEncodingNameByCommandId(
          sorted_encoding_list_[i].encoding_id) == current_encoding) {
        gtk_combo_box_set_active(GTK_COMBO_BOX(default_encoding_combobox_), i);
        break;
      }
    }
  }
}

void FontsPageGtk::SetFontsFromButton(StringPrefMember* name_pref,
                        IntegerPrefMember* size_pref,
                        GtkFontButton* font_button) {
  PangoFontDescription* desc = pango_font_description_from_string(
      gtk_font_button_get_font_name(font_button));
  int size = pango_font_description_get_size(desc);
  name_pref->SetValue(UTF8ToWide(pango_font_description_get_family(desc)));
  size_pref->SetValue(size / PANGO_SCALE);
  pango_font_description_free(desc);
  // Reset the button font in px, since the chooser will have set it in points.
  // Also, both sans and serif share the same size so we need to update them
  // both.
  NotifyPrefChanged(NULL);
}

// static
void FontsPageGtk::OnSerifFontSet(GtkFontButton* font_button,
                                  FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->serif_name_,
                                 &fonts_page->variable_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnSansFontSet(GtkFontButton* font_button,
                                 FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->sans_serif_name_,
                                 &fonts_page->variable_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnFixedFontSet(GtkFontButton* font_button,
                                  FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->fixed_width_name_,
                                 &fonts_page->fixed_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnDefaultEncodingChanged(GtkComboBox* combo_box,
                                            FontsPageGtk* fonts_page) {
  int index = gtk_combo_box_get_active(combo_box);
  if (index < 0 ||
      static_cast<size_t>(index) >= fonts_page->sorted_encoding_list_.size()) {
    NOTREACHED();
    return;
  }
  fonts_page->default_encoding_.SetValue(
      CharacterEncoding::GetCanonicalEncodingNameByCommandId(
          fonts_page->sorted_encoding_list_[index].encoding_id));
}
<commit_msg>Gtk Font options: Separate font family and size by comma to work around Gtk issue.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/options/fonts_page_gtk.h"

#include "app/l10n_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/gtk/options/options_layout_gtk.h"
#include "chrome/common/gtk_util.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"

namespace {

// Make a Gtk font name string from a font family name and pixel size.
std::string MakeFontName(std::wstring family_name, int pixel_size) {
  std::string fontname;
  // TODO(mattm): We can pass in the size in pixels (px), and the font button
  // actually honors it, but when you open the selector it interprets it as
  // points.  See crbug.com/17857
  SStringPrintf(&fontname, "%s, %dpx", WideToUTF8(family_name).c_str(),
                pixel_size);
  return fontname;
}

}  // namespace

FontsPageGtk::FontsPageGtk(Profile* profile) : OptionsPageBase(profile) {
  Init();
}

FontsPageGtk::~FontsPageGtk() {
}

void FontsPageGtk::Init() {
  OptionsLayoutBuilderGtk options_builder;

  serif_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(serif_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(serif_font_button_), TRUE);
  g_signal_connect(serif_font_button_, "font-set", G_CALLBACK(OnSerifFontSet),
                   this);

  sans_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(sans_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(sans_font_button_), TRUE);
  g_signal_connect(sans_font_button_, "font-set", G_CALLBACK(OnSansFontSet),
                   this);

  fixed_font_button_ = gtk_font_button_new();
  gtk_font_button_set_use_font(GTK_FONT_BUTTON(fixed_font_button_), TRUE);
  gtk_font_button_set_use_size(GTK_FONT_BUTTON(fixed_font_button_), TRUE);
  g_signal_connect(fixed_font_button_, "font-set", G_CALLBACK(OnFixedFontSet),
                   this);

  GtkWidget* font_controls = gtk_util::CreateLabeledControlsGroup(NULL,
      l10n_util::GetStringUTF8(
          IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SERIF_LABEL).c_str(),
      serif_font_button_,
      l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_SANS_SERIF_LABEL).c_str(),
      sans_font_button_,
      l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SELECTOR_FIXED_WIDTH_LABEL).c_str(),
      fixed_font_button_,
      NULL);

  options_builder.AddOptionGroup(l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_FONT_TITLE),
      font_controls, false);

  InitDefaultEncodingComboBox();
  std::string encoding_group_description = l10n_util::GetStringUTF8(
      IDS_FONT_LANGUAGE_SETTING_FONT_DEFAULT_ENCODING_SELECTOR_LABEL);
  GtkWidget* encoding_controls = gtk_util::CreateLabeledControlsGroup(NULL,
      encoding_group_description.c_str(),
      default_encoding_combobox_,
      NULL);
  options_builder.AddOptionGroup(l10n_util::GetStringUTF8(
        IDS_FONT_LANGUAGE_SETTING_FONT_SUB_DIALOG_ENCODING_TITLE),
      encoding_controls, false);

  page_ = options_builder.get_page_widget();

  serif_name_.Init(prefs::kWebKitSerifFontFamily, profile()->GetPrefs(), this);
  sans_serif_name_.Init(prefs::kWebKitSansSerifFontFamily,
                        profile()->GetPrefs(), this);
  variable_width_size_.Init(prefs::kWebKitDefaultFontSize,
                            profile()->GetPrefs(), this);

  fixed_width_name_.Init(prefs::kWebKitFixedFontFamily, profile()->GetPrefs(),
                         this);
  fixed_width_size_.Init(prefs::kWebKitDefaultFixedFontSize,
                         profile()->GetPrefs(), this);

  default_encoding_.Init(prefs::kDefaultCharset, profile()->GetPrefs(), this);

  NotifyPrefChanged(NULL);
}

void FontsPageGtk::InitDefaultEncodingComboBox() {
  default_encoding_combobox_ = gtk_combo_box_new_text();
  g_signal_connect(G_OBJECT(default_encoding_combobox_), "changed",
                   G_CALLBACK(OnDefaultEncodingChanged), this);
  int canonical_encoding_names_length =
      CharacterEncoding::GetSupportCanonicalEncodingCount();
  // Initialize the vector of all sorted encodings according to current
  // UI locale.
  std::string locale = g_browser_process->GetApplicationLocale();
  for (int i = 0; i < canonical_encoding_names_length; i++) {
    sorted_encoding_list_.push_back(CharacterEncoding::EncodingInfo(
        CharacterEncoding::GetEncodingCommandIdByIndex(i)));
  }
  l10n_util::SortVectorWithStringKey(locale, &sorted_encoding_list_, true);
  for (size_t i = 0; i < sorted_encoding_list_.size(); i++) {
    gtk_combo_box_append_text(
        GTK_COMBO_BOX(default_encoding_combobox_),
        WideToUTF8(sorted_encoding_list_[i].encoding_display_name).c_str());
  }
}

void FontsPageGtk::NotifyPrefChanged(const std::wstring* pref_name) {
  if (!pref_name || *pref_name == prefs::kWebKitSerifFontFamily ||
      *pref_name == prefs::kWebKitDefaultFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(serif_font_button_),
        MakeFontName(serif_name_.GetValue(),
          variable_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kWebKitSansSerifFontFamily ||
      *pref_name == prefs::kWebKitDefaultFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(sans_font_button_),
        MakeFontName(sans_serif_name_.GetValue(),
          variable_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kWebKitFixedFontFamily ||
      *pref_name == prefs::kWebKitDefaultFixedFontSize) {
    gtk_font_button_set_font_name(GTK_FONT_BUTTON(fixed_font_button_),
        MakeFontName(fixed_width_name_.GetValue(),
          fixed_width_size_.GetValue()).c_str());
  }
  if (!pref_name || *pref_name == prefs::kDefaultCharset) {
    const std::wstring current_encoding = default_encoding_.GetValue();
    for (size_t i = 0; i < sorted_encoding_list_.size(); i++) {
      if (CharacterEncoding::GetCanonicalEncodingNameByCommandId(
          sorted_encoding_list_[i].encoding_id) == current_encoding) {
        gtk_combo_box_set_active(GTK_COMBO_BOX(default_encoding_combobox_), i);
        break;
      }
    }
  }
}

void FontsPageGtk::SetFontsFromButton(StringPrefMember* name_pref,
                        IntegerPrefMember* size_pref,
                        GtkFontButton* font_button) {
  PangoFontDescription* desc = pango_font_description_from_string(
      gtk_font_button_get_font_name(font_button));
  int size = pango_font_description_get_size(desc);
  name_pref->SetValue(UTF8ToWide(pango_font_description_get_family(desc)));
  size_pref->SetValue(size / PANGO_SCALE);
  pango_font_description_free(desc);
  // Reset the button font in px, since the chooser will have set it in points.
  // Also, both sans and serif share the same size so we need to update them
  // both.
  NotifyPrefChanged(NULL);
}

// static
void FontsPageGtk::OnSerifFontSet(GtkFontButton* font_button,
                                  FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->serif_name_,
                                 &fonts_page->variable_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnSansFontSet(GtkFontButton* font_button,
                                 FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->sans_serif_name_,
                                 &fonts_page->variable_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnFixedFontSet(GtkFontButton* font_button,
                                  FontsPageGtk* fonts_page) {
  fonts_page->SetFontsFromButton(&fonts_page->fixed_width_name_,
                                 &fonts_page->fixed_width_size_,
                                 font_button);
}

// static
void FontsPageGtk::OnDefaultEncodingChanged(GtkComboBox* combo_box,
                                            FontsPageGtk* fonts_page) {
  int index = gtk_combo_box_get_active(combo_box);
  if (index < 0 ||
      static_cast<size_t>(index) >= fonts_page->sorted_encoding_list_.size()) {
    NOTREACHED();
    return;
  }
  fonts_page->default_encoding_.SetValue(
      CharacterEncoding::GetCanonicalEncodingNameByCommandId(
          fonts_page->sorted_encoding_list_[index].encoding_id));
}
<|endoftext|>