<commit_before>#include <re2/re2.h>
#include <string>
#include <iostream>
#include <vector>

using namespace std;

static int maxMemoryBudget = 128 << 20; // 128 MiB

typedef struct {
    bool hasMatch;
    int numGroups;
    char** groups;
} REMatchResult;

/**
 * A multi match object which contains either:
 *  - A list of group matches (individual groups)
 *  - A list of regular matches (one group per match)
 */
typedef struct {
    /**
     * Length of either groupMatches or matches (depending on value of hasGroupMatches)
     */
    int numMatches;
    /**
     * If this result contains group matches, contains the number of groups,
     * i.e. the number of elements in every groupMatches element.
     * Undefined if groupMatches == NULL
     * At least one (in case )
     */
    int numElements;
    /**
     * Only filled if this result has group matches (else NULL)
     */
    char*** groupMatches;
} REMultiMatchResult;

/**
 * Lookup table that maps the Python anchor arg to actual anchors.
 */
static const re2::RE2::Anchor anchorLUT[] = {
    re2::RE2::UNANCHORED, re2::RE2::ANCHOR_BOTH, re2::RE2::ANCHOR_START};

/**
 * Create arg array from StringPiece array.
 * Caller must deallocate args with delete[]
 */
RE2::Arg* stringPiecesToArgs(re2::StringPiece* spc, int n) {
    RE2::Arg* args = new RE2::Arg[n]();
    for (int i = 0; i < n; ++i) {
        args[i] = &spc[i];
    }
    return args;
}

/**
 * Copy a StringPiece array to a C string list,
 * each level of which is allocated using new[]
 */
char** copyGroups(const re2::StringPiece* groupsSrc, int numGroups) {
    char** groups = new char*[numGroups];
    for (int i = 0; i < numGroups; ++i) {
        char* group = new char[groupsSrc[i].size() + 1];
        group[groupsSrc[i].size()] = 0; //Insert C terminator
        //Copy actual string
        memcpy(group, groupsSrc[i].data(), groupsSrc[i].size());
        groups[i] = group;
    }
    return groups;
}

extern "C" {
    re2::RE2* RE2_new(const char* pattern, bool caseInsensitive) {
        re2::RE2::Options options;
        options.Copy(re2::RE2::Quiet);
        if(caseInsensitive) {
            options.set_case_sensitive(false);
        }
        options.set_max_mem(maxMemoryBudget);
        re2::RE2* ptr = new re2::RE2(pattern, options);
        return ptr;
    }

    int NumCapturingGroups(re2::RE2* re_obj) {
        return re_obj->NumberOfCapturingGroups();
    }

    void FreeREMatchResult(REMatchResult mr) {
        if(mr.groups != NULL) {
            for (int i = 0; i < mr.numGroups; ++i) {
                if(mr.groups[i] != NULL) {
                    delete[] mr.groups[i];
                }
            }
            delete[] mr.groups;
            mr.groups = NULL;
        }
    }

    void FreeREMultiMatchResult(REMultiMatchResult mr) {
        if(mr.groupMatches != NULL) {
            for (int i = 0; i < mr.numMatches; ++i) {
                if(mr.groupMatches[i] != NULL) {
                    for (int j = 0; j < mr.numElements; ++j) {
                        if(mr.groupMatches[i][j] != NULL) {
                            delete[] mr.groupMatches[i][j];
                        }
                    }
                    delete[] mr.groupMatches[i];
                    mr.groupMatches[i] = NULL;
                }
            }
            delete[] mr.groupMatches;
            mr.groupMatches = NULL;
        }
    }

    REMultiMatchResult FindAllMatches(re2::RE2* re_obj, const char* dataArg, int anchorArg) {
        re2::StringPiece data(dataArg);
        if(anchorArg >= 2) {
            anchorArg = 0; //Should not happen
        }
        re2::RE2::Anchor anchor = anchorLUT[anchorArg];
        //Initialize return arg
        REMultiMatchResult ret;
        ret.numMatches = 0;
        ret.groupMatches = NULL;
        //Map anchor for easier Python iface
        int numGroups = re_obj->NumberOfCapturingGroups();
        ret.numElements = max(1, numGroups);
        int pos = 0;
        int endidx = data.size();
        //Allocate temporary match array
        int nmatch = 1 + numGroups;
        //We don't know the size of this in advance, so we'll need to allocate now
        vector<re2::StringPiece*> allMatches;
        /**
         * Iterate over all non-overlapping (!) matches
         */
        while(true) {
            //Perform match
            re2::StringPiece* matchTmp = new re2::StringPiece[nmatch];
            bool hasMatch = re_obj->Match(data, pos, endidx,
                 anchor, matchTmp, nmatch);
            if(!hasMatch) {
                delete[] matchTmp;
                break;
            }
            //Add matchlist
            allMatches.push_back(matchTmp);
            //Increment position pointer so we get the next hit
            // We are returning non-overlapping matches, so this is OK
            if(matchTmp[0].size() == 0) {
                pos++;
            } else {
                pos += matchTmp[0].size();
            }
        }
        //Compute final size
        ret.numMatches = allMatches.size();
        //Convert match vector to group vector (3D)
        ret.groupMatches = new char**[allMatches.size()];
        for (size_t i = 0; i < allMatches.size(); ++i) {
            //re.findall behaviour: 0 groups -> 1 result,
            // 1 group -> 1 result, n > 1 groups -> n results
            if(numGroups >= 1) { //Do not emit full match
                ret.groupMatches[i] = copyGroups(allMatches[i] + 1, ret.numElements);
            } else { //Emit only full match
                ret.groupMatches[i] = copyGroups(allMatches[i], 1);
            }
        }
        //Cleanup
        for (size_t i = 0; i < allMatches.size(); ++i) {
            if(allMatches[i] != NULL) {
                delete[] allMatches[i];
            }
        }
        return ret;
    }

    REMatchResult FindSingleMatch(re2::RE2* re_obj, const char* dataArg, bool fullMatch) {
        re2::StringPiece data(dataArg);
        REMatchResult ret;
        ret.numGroups = re_obj->NumberOfCapturingGroups() + 1;
        //Declare group target array
        re2::StringPiece* groups = new re2::StringPiece[ret.numGroups]();
        //Perform either
        re2::RE2::Anchor anchor = fullMatch ? re2::RE2::ANCHOR_BOTH : re2::RE2::UNANCHORED;
        ret.hasMatch = re_obj->Match(data, 0, data.size(),
                anchor, groups, ret.numGroups);
        //Copy groups
        if(ret.hasMatch) {
            ret.groups = copyGroups(groups, ret.numGroups);
        } else {
            ret.groups = NULL;
        }
        //Cleanup
        delete[] groups;
        //Return
        return ret;
    }

    void RE2_delete(re2::RE2* re_obj) {
        delete re_obj;
    }

    string* RE2_GlobalReplace(re2::RE2* re_obj, const char* str, const char* rewrite) {
        string* ptr_s = new string(str);
        re2::StringPiece sp(rewrite);

        re2::RE2::GlobalReplace(ptr_s, *re_obj, sp);
        return ptr_s;
    }

    const char* get_c_str(string* ptr_str) {
        if(ptr_str == NULL) {
            return NULL;
        }
        return ptr_str->c_str();
    }

    void RE2_delete_string_ptr(string* ptr) {
        delete ptr;
    }

    const char* get_error_msg(re2::RE2* re_obj) {
        if(!re_obj) {
            return "";
        }
        string* ptr_s = (string*) &(re_obj->error());
        return get_c_str(ptr_s);
    }

    bool ok(re2::RE2* re_obj) {
        if(!re_obj) {
            return false;
        }
        return re_obj->ok();
    }

    void RE2_SetMaxMemory(int maxmem) {
        maxMemoryBudget = maxmem;
    }

}
<commit_msg>Remove unused C++ function<commit_after>#include <re2/re2.h>
#include <string>
#include <iostream>
#include <vector>

using namespace std;

static int maxMemoryBudget = 128 << 20; // 128 MiB

typedef struct {
    bool hasMatch;
    int numGroups;
    char** groups;
} REMatchResult;

/**
 * A multi match object which contains either:
 *  - A list of group matches (individual groups)
 *  - A list of regular matches (one group per match)
 */
typedef struct {
    /**
     * Length of either groupMatches or matches (depending on value of hasGroupMatches)
     */
    int numMatches;
    /**
     * If this result contains group matches, contains the number of groups,
     * i.e. the number of elements in every groupMatches element.
     * Undefined if groupMatches == NULL
     * At least one (in case )
     */
    int numElements;
    /**
     * Only filled if this result has group matches (else NULL)
     */
    char*** groupMatches;
} REMultiMatchResult;

/**
 * Lookup table that maps the Python anchor arg to actual anchors.
 */
static const re2::RE2::Anchor anchorLUT[] = {
    re2::RE2::UNANCHORED, re2::RE2::ANCHOR_BOTH, re2::RE2::ANCHOR_START};

/**
 * Copy a StringPiece array to a C string list,
 * each level of which is allocated using new[]
 */
char** copyGroups(const re2::StringPiece* groupsSrc, int numGroups) {
    char** groups = new char*[numGroups];
    for (int i = 0; i < numGroups; ++i) {
        char* group = new char[groupsSrc[i].size() + 1];
        group[groupsSrc[i].size()] = 0; //Insert C terminator
        //Copy actual string
        memcpy(group, groupsSrc[i].data(), groupsSrc[i].size());
        groups[i] = group;
    }
    return groups;
}

extern "C" {
    re2::RE2* RE2_new(const char* pattern, bool caseInsensitive) {
        re2::RE2::Options options;
        options.Copy(re2::RE2::Quiet);
        if(caseInsensitive) {
            options.set_case_sensitive(false);
        }
        options.set_max_mem(maxMemoryBudget);
        re2::RE2* ptr = new re2::RE2(pattern, options);
        return ptr;
    }

    int NumCapturingGroups(re2::RE2* re_obj) {
        return re_obj->NumberOfCapturingGroups();
    }

    void FreeREMatchResult(REMatchResult mr) {
        if(mr.groups != NULL) {
            for (int i = 0; i < mr.numGroups; ++i) {
                if(mr.groups[i] != NULL) {
                    delete[] mr.groups[i];
                }
            }
            delete[] mr.groups;
            mr.groups = NULL;
        }
    }

    void FreeREMultiMatchResult(REMultiMatchResult mr) {
        if(mr.groupMatches != NULL) {
            for (int i = 0; i < mr.numMatches; ++i) {
                if(mr.groupMatches[i] != NULL) {
                    for (int j = 0; j < mr.numElements; ++j) {
                        if(mr.groupMatches[i][j] != NULL) {
                            delete[] mr.groupMatches[i][j];
                        }
                    }
                    delete[] mr.groupMatches[i];
                    mr.groupMatches[i] = NULL;
                }
            }
            delete[] mr.groupMatches;
            mr.groupMatches = NULL;
        }
    }

    REMultiMatchResult FindAllMatches(re2::RE2* re_obj, const char* dataArg, int anchorArg) {
        re2::StringPiece data(dataArg);
        if(anchorArg >= 2) {
            anchorArg = 0; //Should not happen
        }
        re2::RE2::Anchor anchor = anchorLUT[anchorArg];
        //Initialize return arg
        REMultiMatchResult ret;
        ret.numMatches = 0;
        ret.groupMatches = NULL;
        //Map anchor for easier Python iface
        int numGroups = re_obj->NumberOfCapturingGroups();
        ret.numElements = max(1, numGroups);
        int pos = 0;
        int endidx = data.size();
        //Allocate temporary match array
        int nmatch = 1 + numGroups;
        //We don't know the size of this in advance, so we'll need to allocate now
        vector<re2::StringPiece*> allMatches;
        /**
         * Iterate over all non-overlapping (!) matches
         */
        while(true) {
            //Perform match
            re2::StringPiece* matchTmp = new re2::StringPiece[nmatch];
            bool hasMatch = re_obj->Match(data, pos, endidx,
                 anchor, matchTmp, nmatch);
            if(!hasMatch) {
                delete[] matchTmp;
                break;
            }
            //Add matchlist
            allMatches.push_back(matchTmp);
            //Increment position pointer so we get the next hit
            // We are returning non-overlapping matches, so this is OK
            if(matchTmp[0].size() == 0) {
                pos++;
            } else {
                pos += matchTmp[0].size();
            }
        }
        //Compute final size
        ret.numMatches = allMatches.size();
        //Convert match vector to group vector (3D)
        ret.groupMatches = new char**[allMatches.size()];
        for (size_t i = 0; i < allMatches.size(); ++i) {
            //re.findall behaviour: 0 groups -> 1 result,
            // 1 group -> 1 result, n > 1 groups -> n results
            if(numGroups >= 1) { //Do not emit full match
                ret.groupMatches[i] = copyGroups(allMatches[i] + 1, ret.numElements);
            } else { //Emit only full match
                ret.groupMatches[i] = copyGroups(allMatches[i], 1);
            }
        }
        //Cleanup
        for (size_t i = 0; i < allMatches.size(); ++i) {
            if(allMatches[i] != NULL) {
                delete[] allMatches[i];
            }
        }
        return ret;
    }

    REMatchResult FindSingleMatch(re2::RE2* re_obj, const char* dataArg, bool fullMatch) {
        re2::StringPiece data(dataArg);
        REMatchResult ret;
        ret.numGroups = re_obj->NumberOfCapturingGroups() + 1;
        //Declare group target array
        re2::StringPiece* groups = new re2::StringPiece[ret.numGroups]();
        //Perform either
        re2::RE2::Anchor anchor = fullMatch ? re2::RE2::ANCHOR_BOTH : re2::RE2::UNANCHORED;
        ret.hasMatch = re_obj->Match(data, 0, data.size(),
                anchor, groups, ret.numGroups);
        //Copy groups
        if(ret.hasMatch) {
            ret.groups = copyGroups(groups, ret.numGroups);
        } else {
            ret.groups = NULL;
        }
        //Cleanup
        delete[] groups;
        //Return
        return ret;
    }

    void RE2_delete(re2::RE2* re_obj) {
        delete re_obj;
    }

    string* RE2_GlobalReplace(re2::RE2* re_obj, const char* str, const char* rewrite) {
        string* ptr_s = new string(str);
        re2::StringPiece sp(rewrite);

        re2::RE2::GlobalReplace(ptr_s, *re_obj, sp);
        return ptr_s;
    }

    const char* get_c_str(string* ptr_str) {
        if(ptr_str == NULL) {
            return NULL;
        }
        return ptr_str->c_str();
    }

    void RE2_delete_string_ptr(string* ptr) {
        delete ptr;
    }

    const char* get_error_msg(re2::RE2* re_obj) {
        if(!re_obj) {
            return "";
        }
        string* ptr_s = (string*) &(re_obj->error());
        return get_c_str(ptr_s);
    }

    bool ok(re2::RE2* re_obj) {
        if(!re_obj) {
            return false;
        }
        return re_obj->ok();
    }

    void RE2_SetMaxMemory(int maxmem) {
        maxMemoryBudget = maxmem;
    }

}
<|endoftext|>


<commit_before>#include "ff_spans.h"

#include <sstream>
#include <cassert>
#include <cmath>

#include "filelib.h"
#include "stringlib.h"
#include "sentence_metadata.h"
#include "lattice.h"
#include "fdict.h"
#include "verbose.h"

using namespace std;

// log transform to make long spans cluster together
// but preserve differences
int SpanSizeTransform(unsigned span_size) {
  if (!span_size) return 0;
  return static_cast<int>(log(span_size+1) / log(1.39)) - 1;
}

SpanFeatures::SpanFeatures(const string& param) :
    kS(TD::Convert("S") * -1),
    kX(TD::Convert("X") * -1),
    use_collapsed_features_(false) {
  string mapfile = param;
  string valfile;
  vector<string> toks;
  Tokenize(param, ' ', &toks);
  if (toks.size() == 2) { mapfile = toks[0]; valfile = toks[1]; }
  if (mapfile.size() > 0) {
    int lc = 0;
    if (!SILENT) { cerr << "Reading word map for SpanFeatures from " << param << endl; }
    ReadFile rf(mapfile);
    istream& in = *rf.stream();
    string line;
    vector<WordID> v;
    while(in) {
      ++lc;
      getline(in, line);
      if (line.empty()) continue;
      v.clear();
      TD::ConvertSentence(line, &v);
      if (v.size() != 2) {
        cerr << "Error reading line " << lc << ": " << line << endl;
        abort();
      }
      word2class_[v[0]] = v[1];
    }
    word2class_[TD::Convert("BOS")] = TD::Convert("BOS");
    word2class_[TD::Convert("EOS")] = TD::Convert("EOS");
    oov_ = TD::Convert("OOV");
  }

  if (valfile.size() > 0) {
    use_collapsed_features_ = true;
    fid_beg_ = FD::Convert("SpanBegin");
    fid_end_ = FD::Convert("SpanEnd");
    fid_span_s_ = FD::Convert("SSpanContext");
    fid_span_ = FD::Convert("XSpanContext");
    ReadFile rf(valfile);
    if (!SILENT) { cerr << "  Loading span scores from " << valfile << endl; }
    istream& in = *rf.stream();
    string line;
    while(in) {
      getline(in, line);
      if (line.size() == 0 || line[0] == '#') { continue; }
      istringstream in(line);
      string feat_name;
      double weight;
      in >> feat_name >> weight;
      feat2val_[feat_name] = weight;
    }
  }
}

void SpanFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  assert(edge.j_ < end_span_ids_.size());
  assert(edge.j_ >= 0);
  assert(edge.i_ < beg_span_ids_.size());
  assert(edge.i_ >= 0);
  if (use_collapsed_features_) {
    features->set_value(fid_end_, end_span_vals_[edge.j_]);
    features->set_value(fid_beg_, beg_span_vals_[edge.i_]);
    if (edge.rule_->lhs_ == kS)
      features->set_value(fid_span_s_, span_vals_(edge.i_,edge.j_).second);
    else
      features->set_value(fid_span_, span_vals_(edge.i_,edge.j_).first);
  } else {  // non-collapsed features:
    features->set_value(end_span_ids_[edge.j_], 1);
    features->set_value(beg_span_ids_[edge.i_], 1);
    features->set_value(end_bigram_ids_[edge.j_], 1);
    features->set_value(beg_bigram_ids_[edge.i_], 1);
    if (edge.rule_->lhs_ == kS) {
      features->set_value(span_feats_(edge.i_,edge.j_).second, 1);
      features->set_value(len_span_feats_(edge.i_,edge.j_).second, 1);
    } else {
      features->set_value(span_feats_(edge.i_,edge.j_).first, 1);
      features->set_value(len_span_feats_(edge.i_,edge.j_).first, 1);
    }
  }
}

WordID SpanFeatures::MapIfNecessary(const WordID& w) const {
  if (word2class_.empty()) return w;
  map<WordID,WordID>::const_iterator it = word2class_.find(w);
  if (it == word2class_.end()) return oov_;
  return it->second;
}

void SpanFeatures::PrepareForInput(const SentenceMetadata& smeta) {
  const Lattice& lattice = smeta.GetSourceLattice();
  const WordID eos = TD::Convert("EOS");  // right of the last source word
  const WordID bos = TD::Convert("BOS");  // left of the first source word
  beg_span_ids_.resize(lattice.size() + 1);
  end_span_ids_.resize(lattice.size() + 1);
  span_feats_.resize(lattice.size() + 1, lattice.size() + 1);
  beg_bigram_ids_.resize(lattice.size() + 1);
  end_bigram_ids_.resize(lattice.size() + 1);
  len_span_feats_.resize(lattice.size() + 1, lattice.size() + 1);
  if (use_collapsed_features_) {
    beg_span_vals_.resize(lattice.size() + 1);
    end_span_vals_.resize(lattice.size() + 1);
    span_vals_.resize(lattice.size() + 1, lattice.size() + 1);
  }
  for (int i = 0; i <= lattice.size(); ++i) {
    WordID word = eos;
    WordID bword = bos;
    if (i > 0)
      bword = lattice[i-1][0].label;
    bword = MapIfNecessary(bword);
    if (i < lattice.size())
      word = lattice[i][0].label;  // rather arbitrary for lattices
    word = MapIfNecessary(word);
    ostringstream sfid;
    sfid << "ES:" << TD::Convert(word);
    end_span_ids_[i] = FD::Convert(sfid.str());
    ostringstream esbiid;
    esbiid << "EBI:" << TD::Convert(bword) << "_" << TD::Convert(word);
    end_bigram_ids_[i] = FD::Convert(esbiid.str());
    ostringstream bsbiid;
    bsbiid << "BBI:" << TD::Convert(bword) << "_" << TD::Convert(word);
    beg_bigram_ids_[i] = FD::Convert(bsbiid.str());
    ostringstream bfid;
    bfid << "BS:" << TD::Convert(bword);
    beg_span_ids_[i] = FD::Convert(bfid.str());
    if (use_collapsed_features_) {
      end_span_vals_[i] = feat2val_[sfid.str()] + feat2val_[esbiid.str()];
      beg_span_vals_[i] = feat2val_[bfid.str()] + feat2val_[bsbiid.str()];
    }
  }
  for (int i = 0; i <= lattice.size(); ++i) {
    WordID bword = bos;
    if (i > 0)
      bword = lattice[i-1][0].label;
    bword = MapIfNecessary(bword);
    for (int j = 0; j <= lattice.size(); ++j) {
      WordID word = eos;
      if (j < lattice.size())
        word = lattice[j][0].label;
      word = MapIfNecessary(word);
      ostringstream pf;
      pf << "S:" << TD::Convert(bword) << "_" << TD::Convert(word);
      span_feats_(i,j).first = FD::Convert(pf.str());
      span_feats_(i,j).second = FD::Convert("S_" + pf.str());
      ostringstream lf;
      const unsigned span_size = (i < j ? j - i : i - j);
      lf << "LS:" << SpanSizeTransform(span_size) << "_" << TD::Convert(bword) << "_" << TD::Convert(word);
      len_span_feats_(i,j).first = FD::Convert(lf.str());
      len_span_feats_(i,j).second = FD::Convert("S_" + lf.str());
      if (use_collapsed_features_) {
        span_vals_(i,j).first = feat2val_[pf.str()] + feat2val_[lf.str()];
        span_vals_(i,j).second = feat2val_["S_" + pf.str()] + feat2val_["S_" + lf.str()];
      }
    }
  }
}

RuleNgramFeatures::RuleNgramFeatures(const std::string& param) {
}

void RuleNgramFeatures::PrepareForInput(const SentenceMetadata& smeta) {
//  std::map<const TRule*, SparseVector<double> >
  rule2_feats_.clear();
}

void RuleNgramFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  map<const TRule*, SparseVector<double> >::iterator it = rule2_feats_.find(edge.rule_.get());
  if (it == rule2_feats_.end()) {
    const TRule& rule = *edge.rule_;
    it = rule2_feats_.insert(make_pair(&rule, SparseVector<double>())).first;
    SparseVector<double>& f = it->second;
    string prev = "<r>";
    for (int i = 0; i < rule.f_.size(); ++i) {
      WordID w = rule.f_[i];
      if (w < 0) w = -w;
      assert(w > 0);
      const string& cur = TD::Convert(w);
      ostringstream os;
      os << "RB:" << prev << '_' << cur;
      const int fid = FD::Convert(os.str());
      if (fid <= 0) return;
      f.add_value(fid, 1.0);
      prev = cur;
    }
    ostringstream os;
    os << "RB:" << prev << '_' << "</r>";
    f.set_value(FD::Convert(os.str()), 1.0);
  }
  (*features) += it->second;
}

inline bool IsArity2RuleReordered(const TRule& rule) {
  const vector<WordID>& e = rule.e_;
  for (int i = 0; i < e.size(); ++i) {
    if (e[i] <= 0) { return e[i] < 0; }
  }
  cerr << "IsArity2RuleReordered failed on:\n" << rule.AsString() << endl;
  abort();
}

// Chiang, Marton, Resnik 2008 "fine-grained" reordering features
CMR2008ReorderingFeatures::CMR2008ReorderingFeatures(const std::string& param) :
    kS(TD::Convert("S") * -1),
    use_collapsed_features_(false) {
  if (param.size() > 0) {
    use_collapsed_features_ = true;
    assert(!"not implemented"); // TODO
  } else {
    unconditioned_fids_.first = FD::Convert("CMRMono");
    unconditioned_fids_.second = FD::Convert("CMRReorder");
    fids_.resize(16); fids_[0].first = fids_[0].second = -1;
    // since I use a log transform, I go a bit higher than David, who bins everything > 10
    for (int span_size = 1; span_size <= 15; ++span_size) {
      ostringstream m, r;
      m << "CMRMono_" << SpanSizeTransform(span_size);
      fids_[span_size].first = FD::Convert(m.str());
      r << "CMRReorder_" << SpanSizeTransform(span_size);
      fids_[span_size].second = FD::Convert(r.str());
    }
  }
}

void CMR2008ReorderingFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  if (edge.Arity() != 2) return;
  if (edge.rule_->lhs_ == kS) return;
  assert(edge.i_ >= 0);
  assert(edge.j_ > edge.i_);
  const bool is_reordered = IsArity2RuleReordered(*edge.rule_);
  const unsigned span_size = edge.j_ - edge.i_;
  if (use_collapsed_features_) {
    assert(!"not impl"); // TODO
  } else {
    if (is_reordered) {
      features->set_value(unconditioned_fids_.second, 1.0);
      features->set_value(fids_[span_size].second, 1.0);
    } else {
      features->set_value(unconditioned_fids_.first, 1.0);
      features->set_value(fids_[span_size].first, 1.0);
    }
  }
}

<commit_msg>escape feature names<commit_after>#include "ff_spans.h"

#include <sstream>
#include <cassert>
#include <cmath>

#include "filelib.h"
#include "stringlib.h"
#include "sentence_metadata.h"
#include "lattice.h"
#include "fdict.h"
#include "verbose.h"

using namespace std;

namespace {
  string Escape(const string& x) {
    string y = x;
    for (int i = 0; i < y.size(); ++i) {
      if (y[i] == '=') y[i]='_';
      if (y[i] == ';') y[i]='_';
    }
    return y;
  }
}

// log transform to make long spans cluster together
// but preserve differences
int SpanSizeTransform(unsigned span_size) {
  if (!span_size) return 0;
  return static_cast<int>(log(span_size+1) / log(1.39)) - 1;
}

SpanFeatures::SpanFeatures(const string& param) :
    kS(TD::Convert("S") * -1),
    kX(TD::Convert("X") * -1),
    use_collapsed_features_(false) {
  string mapfile = param;
  string valfile;
  vector<string> toks;
  Tokenize(param, ' ', &toks);
  if (toks.size() == 2) { mapfile = toks[0]; valfile = toks[1]; }
  if (mapfile.size() > 0) {
    int lc = 0;
    if (!SILENT) { cerr << "Reading word map for SpanFeatures from " << param << endl; }
    ReadFile rf(mapfile);
    istream& in = *rf.stream();
    string line;
    vector<WordID> v;
    while(in) {
      ++lc;
      getline(in, line);
      if (line.empty()) continue;
      v.clear();
      TD::ConvertSentence(line, &v);
      if (v.size() != 2) {
        cerr << "Error reading line " << lc << ": " << line << endl;
        abort();
      }
      word2class_[v[0]] = v[1];
    }
    word2class_[TD::Convert("BOS")] = TD::Convert("BOS");
    word2class_[TD::Convert("EOS")] = TD::Convert("EOS");
    oov_ = TD::Convert("OOV");
  }

  if (valfile.size() > 0) {
    use_collapsed_features_ = true;
    fid_beg_ = FD::Convert("SpanBegin");
    fid_end_ = FD::Convert("SpanEnd");
    fid_span_s_ = FD::Convert("SSpanContext");
    fid_span_ = FD::Convert("XSpanContext");
    ReadFile rf(valfile);
    if (!SILENT) { cerr << "  Loading span scores from " << valfile << endl; }
    istream& in = *rf.stream();
    string line;
    while(in) {
      getline(in, line);
      if (line.size() == 0 || line[0] == '#') { continue; }
      istringstream in(line);
      string feat_name;
      double weight;
      in >> feat_name >> weight;
      feat2val_[feat_name] = weight;
    }
  }
}

void SpanFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  assert(edge.j_ < end_span_ids_.size());
  assert(edge.j_ >= 0);
  assert(edge.i_ < beg_span_ids_.size());
  assert(edge.i_ >= 0);
  if (use_collapsed_features_) {
    features->set_value(fid_end_, end_span_vals_[edge.j_]);
    features->set_value(fid_beg_, beg_span_vals_[edge.i_]);
    if (edge.rule_->lhs_ == kS)
      features->set_value(fid_span_s_, span_vals_(edge.i_,edge.j_).second);
    else
      features->set_value(fid_span_, span_vals_(edge.i_,edge.j_).first);
  } else {  // non-collapsed features:
    features->set_value(end_span_ids_[edge.j_], 1);
    features->set_value(beg_span_ids_[edge.i_], 1);
    features->set_value(end_bigram_ids_[edge.j_], 1);
    features->set_value(beg_bigram_ids_[edge.i_], 1);
    if (edge.rule_->lhs_ == kS) {
      features->set_value(span_feats_(edge.i_,edge.j_).second, 1);
      features->set_value(len_span_feats_(edge.i_,edge.j_).second, 1);
    } else {
      features->set_value(span_feats_(edge.i_,edge.j_).first, 1);
      features->set_value(len_span_feats_(edge.i_,edge.j_).first, 1);
    }
  }
}

WordID SpanFeatures::MapIfNecessary(const WordID& w) const {
  if (word2class_.empty()) return w;
  map<WordID,WordID>::const_iterator it = word2class_.find(w);
  if (it == word2class_.end()) return oov_;
  return it->second;
}

void SpanFeatures::PrepareForInput(const SentenceMetadata& smeta) {
  const Lattice& lattice = smeta.GetSourceLattice();
  const WordID eos = TD::Convert("EOS");  // right of the last source word
  const WordID bos = TD::Convert("BOS");  // left of the first source word
  beg_span_ids_.resize(lattice.size() + 1);
  end_span_ids_.resize(lattice.size() + 1);
  span_feats_.resize(lattice.size() + 1, lattice.size() + 1);
  beg_bigram_ids_.resize(lattice.size() + 1);
  end_bigram_ids_.resize(lattice.size() + 1);
  len_span_feats_.resize(lattice.size() + 1, lattice.size() + 1);
  if (use_collapsed_features_) {
    beg_span_vals_.resize(lattice.size() + 1);
    end_span_vals_.resize(lattice.size() + 1);
    span_vals_.resize(lattice.size() + 1, lattice.size() + 1);
  }
  for (int i = 0; i <= lattice.size(); ++i) {
    WordID word = eos;
    WordID bword = bos;
    if (i > 0)
      bword = lattice[i-1][0].label;
    bword = MapIfNecessary(bword);
    if (i < lattice.size())
      word = lattice[i][0].label;  // rather arbitrary for lattices
    word = MapIfNecessary(word);
    ostringstream sfid;
    sfid << "ES:" << TD::Convert(word);
    end_span_ids_[i] = FD::Convert(Escape(sfid.str()));
    ostringstream esbiid;
    esbiid << "EBI:" << TD::Convert(bword) << "_" << TD::Convert(word);
    end_bigram_ids_[i] = FD::Convert(Escape(esbiid.str()));
    ostringstream bsbiid;
    bsbiid << "BBI:" << TD::Convert(bword) << "_" << TD::Convert(word);
    beg_bigram_ids_[i] = FD::Convert(Escape(bsbiid.str()));
    ostringstream bfid;
    bfid << "BS:" << TD::Convert(bword);
    beg_span_ids_[i] = FD::Convert(Escape(bfid.str()));
    if (use_collapsed_features_) {
      end_span_vals_[i] = feat2val_[Escape(sfid.str())] + feat2val_[Escape(esbiid.str())];
      beg_span_vals_[i] = feat2val_[Escape(bfid.str())] + feat2val_[Escape(bsbiid.str())];
    }
  }
  for (int i = 0; i <= lattice.size(); ++i) {
    WordID bword = bos;
    if (i > 0)
      bword = lattice[i-1][0].label;
    bword = MapIfNecessary(bword);
    for (int j = 0; j <= lattice.size(); ++j) {
      WordID word = eos;
      if (j < lattice.size())
        word = lattice[j][0].label;
      word = MapIfNecessary(word);
      ostringstream pf;
      pf << "S:" << TD::Convert(bword) << "_" << TD::Convert(word);
      span_feats_(i,j).first = FD::Convert(Escape(pf.str()));
      span_feats_(i,j).second = FD::Convert(Escape("S_" + pf.str()));
      ostringstream lf;
      const unsigned span_size = (i < j ? j - i : i - j);
      lf << "LS:" << SpanSizeTransform(span_size) << "_" << TD::Convert(bword) << "_" << TD::Convert(word);
      len_span_feats_(i,j).first = FD::Convert(Escape(lf.str()));
      len_span_feats_(i,j).second = FD::Convert(Escape("S_" + lf.str()));
      if (use_collapsed_features_) {
        span_vals_(i,j).first = feat2val_[Escape(pf.str())] + feat2val_[Escape(lf.str())];
        span_vals_(i,j).second = feat2val_[Escape("S_" + pf.str())] + feat2val_[Escape("S_" + lf.str())];
      }
    }
  }
}

RuleNgramFeatures::RuleNgramFeatures(const std::string& param) {
}

void RuleNgramFeatures::PrepareForInput(const SentenceMetadata& smeta) {
//  std::map<const TRule*, SparseVector<double> >
  rule2_feats_.clear();
}

void RuleNgramFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  map<const TRule*, SparseVector<double> >::iterator it = rule2_feats_.find(edge.rule_.get());
  if (it == rule2_feats_.end()) {
    const TRule& rule = *edge.rule_;
    it = rule2_feats_.insert(make_pair(&rule, SparseVector<double>())).first;
    SparseVector<double>& f = it->second;
    string prev = "<r>";
    for (int i = 0; i < rule.f_.size(); ++i) {
      WordID w = rule.f_[i];
      if (w < 0) w = -w;
      assert(w > 0);
      const string& cur = TD::Convert(w);
      ostringstream os;
      os << "RB:" << prev << '_' << cur;
      const int fid = FD::Convert(Escape(os.str()));
      if (fid <= 0) return;
      f.add_value(fid, 1.0);
      prev = cur;
    }
    ostringstream os;
    os << "RB:" << prev << '_' << "</r>";
    f.set_value(FD::Convert(Escape(os.str())), 1.0);
  }
  (*features) += it->second;
}

inline bool IsArity2RuleReordered(const TRule& rule) {
  const vector<WordID>& e = rule.e_;
  for (int i = 0; i < e.size(); ++i) {
    if (e[i] <= 0) { return e[i] < 0; }
  }
  cerr << "IsArity2RuleReordered failed on:\n" << rule.AsString() << endl;
  abort();
}

// Chiang, Marton, Resnik 2008 "fine-grained" reordering features
CMR2008ReorderingFeatures::CMR2008ReorderingFeatures(const std::string& param) :
    kS(TD::Convert("S") * -1),
    use_collapsed_features_(false) {
  if (param.size() > 0) {
    use_collapsed_features_ = true;
    assert(!"not implemented"); // TODO
  } else {
    unconditioned_fids_.first = FD::Convert("CMRMono");
    unconditioned_fids_.second = FD::Convert("CMRReorder");
    fids_.resize(16); fids_[0].first = fids_[0].second = -1;
    // since I use a log transform, I go a bit higher than David, who bins everything > 10
    for (int span_size = 1; span_size <= 15; ++span_size) {
      ostringstream m, r;
      m << "CMRMono_" << SpanSizeTransform(span_size);
      fids_[span_size].first = FD::Convert(m.str());
      r << "CMRReorder_" << SpanSizeTransform(span_size);
      fids_[span_size].second = FD::Convert(r.str());
    }
  }
}

void CMR2008ReorderingFeatures::TraversalFeaturesImpl(const SentenceMetadata& smeta,
                                         const Hypergraph::Edge& edge,
                                         const vector<const void*>& ant_contexts,
                                         SparseVector<double>* features,
                                         SparseVector<double>* estimated_features,
                                         void* context) const {
  if (edge.Arity() != 2) return;
  if (edge.rule_->lhs_ == kS) return;
  assert(edge.i_ >= 0);
  assert(edge.j_ > edge.i_);
  const bool is_reordered = IsArity2RuleReordered(*edge.rule_);
  const unsigned span_size = edge.j_ - edge.i_;
  if (use_collapsed_features_) {
    assert(!"not impl"); // TODO
  } else {
    if (is_reordered) {
      features->set_value(unconditioned_fids_.second, 1.0);
      features->set_value(fids_[span_size].second, 1.0);
    } else {
      features->set_value(unconditioned_fids_.first, 1.0);
      features->set_value(fids_[span_size].first, 1.0);
    }
  }
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Hernan Saez
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Simulation.hpp"
#include "FileSystem.hpp"

#include "Foundation/Log.hpp"
#include "Foundation/Version.hpp"

#include "Concurrency/Async.hpp"

#include "SceneGraph/Camera.hpp"

#include "Rendering/FrameBufferObject.hpp"

#include "Visitors/FetchCameras.hpp"
#include "Visitors/UpdateWorldState.hpp"
#include "Visitors/UpdateRenderState.hpp"
#include "Visitors/StartComponents.hpp"

#include "Simulation/Systems/RenderSystem.hpp"
#include "Simulation/Systems/UpdateSystem.hpp"
#include "Simulation/Systems/DebugSystem.hpp"
#include "Simulation/Systems/StreamingSystem.hpp"

using namespace crimild;

Simulation::Simulation( std::string name, SettingsPtr const &settings )
	: NamedObject( name ),
      _settings( settings ),
      _taskManager( 0 ) // by default, disable background threads
{
	addSystem( crimild::alloc< UpdateSystem >() );
	addSystem( crimild::alloc< RenderSystem >() );
    addSystem( crimild::alloc< DebugSystem >() );
    addSystem( crimild::alloc< StreamingSystem >() );
}

Simulation::~Simulation( void )
{
	stopSystems();
}

void Simulation::start( void )
{
    Log::Info << Version::getDescription() << Log::End;

    startSystems();

    _taskManager.start();
}

bool Simulation::update( void )
{
    auto scene = getScene();

    broadcastMessage( messaging::SimulationWillUpdate { scene } );

    _taskManager.pollMainTasks();

    broadcastMessage( messaging::SimulationDidUpdate { scene } );

	return _taskManager.isRunning();
}

void Simulation::stop( void )
{
    _taskManager.stop();
}

int Simulation::run( void )
{
	start();
    while ( update() ) {
        // do nothing
    }

    stopSystems();  // redundant?

	return 0;
}

void Simulation::addSystem( SystemPtr const &system )
{
	Log::Debug << "Adding system " << system->getName() << Log::End;

	if ( _systems.find( system->getName() ) == _systems.end() ) {
		_systems.insert( std::make_pair( system->getName(), system ) );
	}
}

SystemPtr Simulation::getSystem( std::string name )
{
	return _systems[ name ];
}

void Simulation::startSystems( void )
{
	Log::Debug << "Starting systems" << Log::End;
	for ( auto s : _systems ) {
		if ( s.second != nullptr ) {
			s.second->start();
		}
	}
}

void Simulation::stopSystems( void )
{
	Log::Debug << "Stopping systems" << Log::End;
	for ( auto s : _systems ) {
		if ( s.second != nullptr ) {
			s.second->stop();
		}
	}

    _systems.clear();
}

void Simulation::setScene( SharedPointer< Node > const &scene )
{
	_scene = scene;
	_cameras.clear();

	if ( _scene != nullptr ) {
		_scene->perform( UpdateWorldState() );
		_scene->perform( UpdateRenderState() );
		_scene->perform( StartComponents() );

		FetchCameras fetchCameras;
		_scene->perform( fetchCameras );
        fetchCameras.forEachCamera( [&]( Camera *camera ) {
            _cameras.push_back( camera );
        });
	}

    AssetManager::getInstance()->clear();
    MessageQueue::getInstance()->clear();

    _simulationClock.reset();

	auto renderer = Simulation::getInstance()->getRenderer();
	if ( getMainCamera() != nullptr && renderer != nullptr && renderer->getScreenBuffer() != nullptr ) {
		auto screen = renderer->getScreenBuffer();
		auto aspect = ( float ) screen->getWidth() / ( float ) screen->getHeight();

		if ( getMainCamera() != nullptr ) {
			getMainCamera()->setAspectRatio( aspect );
		}
	}

    broadcastMessage( messaging::SceneChanged { crimild::get_ptr( _scene ) } );
}

void Simulation::loadScene( std::string filename, SharedPointer< SceneBuilder > const &builder )
{
    auto self = this;
    crimild::async( [self, filename, builder] {
        self->broadcastMessage( messaging::LoadScene { filename, builder } );
    });
}

void Simulation::forEachCamera( std::function< void ( Camera * ) > callback )
{
	for ( auto camera : _cameras ) {
		callback( camera );
	}
}

<commit_msg>Clear AssetManager cache before loading a scene<commit_after>/*
 * Copyright (c) 2013, Hernan Saez
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Simulation.hpp"
#include "FileSystem.hpp"

#include "Foundation/Log.hpp"
#include "Foundation/Version.hpp"

#include "Concurrency/Async.hpp"

#include "SceneGraph/Camera.hpp"

#include "Rendering/FrameBufferObject.hpp"

#include "Visitors/FetchCameras.hpp"
#include "Visitors/UpdateWorldState.hpp"
#include "Visitors/UpdateRenderState.hpp"
#include "Visitors/StartComponents.hpp"

#include "Simulation/Systems/RenderSystem.hpp"
#include "Simulation/Systems/UpdateSystem.hpp"
#include "Simulation/Systems/DebugSystem.hpp"
#include "Simulation/Systems/StreamingSystem.hpp"

using namespace crimild;

Simulation::Simulation( std::string name, SettingsPtr const &settings )
	: NamedObject( name ),
      _settings( settings ),
      _taskManager( 0 ) // by default, disable background threads
{
	addSystem( crimild::alloc< UpdateSystem >() );
	addSystem( crimild::alloc< RenderSystem >() );
    addSystem( crimild::alloc< DebugSystem >() );
    addSystem( crimild::alloc< StreamingSystem >() );
}

Simulation::~Simulation( void )
{
	stopSystems();
}

void Simulation::start( void )
{
    Log::Info << Version::getDescription() << Log::End;

    startSystems();

    _taskManager.start();
}

bool Simulation::update( void )
{
    auto scene = getScene();

    broadcastMessage( messaging::SimulationWillUpdate { scene } );

    _taskManager.pollMainTasks();

    broadcastMessage( messaging::SimulationDidUpdate { scene } );

	return _taskManager.isRunning();
}

void Simulation::stop( void )
{
    _taskManager.stop();
}

int Simulation::run( void )
{
	start();
    while ( update() ) {
        // do nothing
    }

    stopSystems();  // redundant?

	return 0;
}

void Simulation::addSystem( SystemPtr const &system )
{
	Log::Debug << "Adding system " << system->getName() << Log::End;

	if ( _systems.find( system->getName() ) == _systems.end() ) {
		_systems.insert( std::make_pair( system->getName(), system ) );
	}
}

SystemPtr Simulation::getSystem( std::string name )
{
	return _systems[ name ];
}

void Simulation::startSystems( void )
{
	Log::Debug << "Starting systems" << Log::End;
	for ( auto s : _systems ) {
		if ( s.second != nullptr ) {
			s.second->start();
		}
	}
}

void Simulation::stopSystems( void )
{
	Log::Debug << "Stopping systems" << Log::End;
	for ( auto s : _systems ) {
		if ( s.second != nullptr ) {
			s.second->stop();
		}
	}

    _systems.clear();
}

void Simulation::setScene( SharedPointer< Node > const &scene )
{
	_scene = scene;
	_cameras.clear();

	if ( _scene != nullptr ) {
		_scene->perform( UpdateWorldState() );
		_scene->perform( UpdateRenderState() );
		_scene->perform( StartComponents() );

		FetchCameras fetchCameras;
		_scene->perform( fetchCameras );
        fetchCameras.forEachCamera( [&]( Camera *camera ) {
            _cameras.push_back( camera );
        });
	}

    MessageQueue::getInstance()->clear();

    _simulationClock.reset();

	auto renderer = Simulation::getInstance()->getRenderer();
	if ( getMainCamera() != nullptr && renderer != nullptr && renderer->getScreenBuffer() != nullptr ) {
		auto screen = renderer->getScreenBuffer();
		auto aspect = ( float ) screen->getWidth() / ( float ) screen->getHeight();

		if ( getMainCamera() != nullptr ) {
			getMainCamera()->setAspectRatio( aspect );
		}
	}

    broadcastMessage( messaging::SceneChanged { crimild::get_ptr( _scene ) } );
}

void Simulation::loadScene( std::string filename, SharedPointer< SceneBuilder > const &builder )
{
    AssetManager::getInstance()->clear();

    auto self = this;
    crimild::async( [self, filename, builder] {
        self->broadcastMessage( messaging::LoadScene { filename, builder } );
    });
}

void Simulation::forEachCamera( std::function< void ( Camera * ) > callback )
{
	for ( auto camera : _cameras ) {
		callback( camera );
	}
}

<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIScrolledContainer.cpp
    created:    1/3/2005
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "elements/CEGUIScrolledContainer.h"
#include "CEGUICoordConverter.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
const String ScrolledContainer::WidgetTypeName("ScrolledContainer");
const String ScrolledContainer::EventNamespace("ScrolledContainer");
const String ScrolledContainer::EventContentChanged("ContentChanged");
const String ScrolledContainer::EventAutoSizeSettingChanged("AutoSizeSettingChanged");

//----------------------------------------------------------------------------//
ScrolledContainerProperties::ContentPaneAutoSized ScrolledContainer::d_autoSizedProperty;
ScrolledContainerProperties::ContentArea          ScrolledContainer::d_contentAreaProperty;
ScrolledContainerProperties::ChildExtentsArea     ScrolledContainer::d_childExtentsAreaProperty;

//----------------------------------------------------------------------------//
ScrolledContainer::ScrolledContainer(const String& type, const String& name) :
    Window(type, name),
    d_contentArea(0, 0, 0, 0),
    d_autosizePane(true)
{
    addScrolledContainerProperties();
}

//----------------------------------------------------------------------------//
ScrolledContainer::~ScrolledContainer(void)
{
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::isContentPaneAutoSized(void) const
{
    return d_autosizePane;
}

//----------------------------------------------------------------------------//
void ScrolledContainer::setContentPaneAutoSized(bool setting)
{
    if (d_autosizePane != setting)
    {
        d_autosizePane = setting;

        // Fire events
        WindowEventArgs args1(this);
        onAutoSizeSettingChanged(args1);
    }
}

//----------------------------------------------------------------------------//
const Rect& ScrolledContainer::getContentArea(void) const
{
    return d_contentArea;
}

//----------------------------------------------------------------------------//
void ScrolledContainer::setContentArea(const Rect& area)
{
    if (!d_autosizePane)
    {
        d_contentArea = area;

        // Fire event
        WindowEventArgs args(this);
        onContentChanged(args);
   }

}

//----------------------------------------------------------------------------//
Rect ScrolledContainer::getChildExtentsArea(void) const
{
    size_t childCount = getChildCount();

    // set up initial content area to match first child.
    if (childCount != 0)
    {
        Window* wnd = getChildAtIdx(0);
        Rect extents(wnd->getArea().asAbsolute(d_pixelSize));

        // control var starts at 1 since we already dealt with 0 above
        for (size_t i = 1; i < childCount; ++i)
        {
            wnd = getChildAtIdx(i);
            Rect area(wnd->getArea().asAbsolute(d_pixelSize));

            if (area.d_left < extents.d_left)
                extents.d_left = area.d_left;

            if (area.d_top < extents.d_top)
                extents.d_top = area.d_top;

            if (area.d_right > extents.d_right)
                extents.d_right = area.d_right;

            if (area.d_bottom > extents.d_bottom)
                extents.d_bottom = area.d_bottom;
        }

        return extents;
    }
    else
    {
        return Rect(0, 0, 0, 0);
    }
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onContentChanged(WindowEventArgs& e)
{
    if (d_autosizePane)
    {
        d_contentArea = getChildExtentsArea();
    }

    fireEvent(EventContentChanged, e, EventNamespace);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onAutoSizeSettingChanged(WindowEventArgs& e)
{
    fireEvent(EventAutoSizeSettingChanged, e, EventNamespace);

    if (d_autosizePane)
    {
        WindowEventArgs args(this);
        onContentChanged(args);
    }
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::handleChildSized(const EventArgs&)
{
    // Fire event that notifies that a child's area has changed.
    WindowEventArgs args(this);
    onContentChanged(args);
    return true;
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::handleChildMoved(const EventArgs&)
{
    // Fire event that notifies that a child's area has changed.
    WindowEventArgs args(this);
    onContentChanged(args);
    return true;
}

//----------------------------------------------------------------------------//
Rect ScrolledContainer::getUnclippedInnerRect_impl(void) const
{
    // return the size of our content as our inner rect.
    return CoordConverter::windowToScreen(*this, d_contentArea);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onChildAdded(WindowEventArgs& e)
{
    Window::onChildAdded(e);

    // subscribe to some events on this child
    d_eventConnections.insert(std::make_pair(e.window,
        e.window->subscribeEvent(Window::EventSized,
            Event::Subscriber(&ScrolledContainer::handleChildSized, this))));
    d_eventConnections.insert(std::make_pair(e.window,
        e.window->subscribeEvent(Window::EventMoved,
            Event::Subscriber(&ScrolledContainer::handleChildMoved, this))));

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onChildRemoved(WindowEventArgs& e)
{
    Window::onChildRemoved(e);

    // disconnect from events for this window.
    ConnectionTracker::iterator conn;
    while ((conn = d_eventConnections.find(e.window)) != d_eventConnections.end())
    {
        conn->second->disconnect();
        d_eventConnections.erase(conn);
    }

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onParentSized(WindowEventArgs& e)
{
    Window::onParentSized(e);

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::addScrolledContainerProperties(void)
{
    addProperty(&d_autoSizedProperty);
    addProperty(&d_contentAreaProperty);
    addProperty(&d_childExtentsAreaProperty);
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<commit_msg>Fix issue where ScrollablePane content had incorrect initial position.<commit_after>/***********************************************************************
    filename:   CEGUIScrolledContainer.cpp
    created:    1/3/2005
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "elements/CEGUIScrolledContainer.h"
#include "CEGUICoordConverter.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
const String ScrolledContainer::WidgetTypeName("ScrolledContainer");
const String ScrolledContainer::EventNamespace("ScrolledContainer");
const String ScrolledContainer::EventContentChanged("ContentChanged");
const String ScrolledContainer::EventAutoSizeSettingChanged("AutoSizeSettingChanged");

//----------------------------------------------------------------------------//
ScrolledContainerProperties::ContentPaneAutoSized ScrolledContainer::d_autoSizedProperty;
ScrolledContainerProperties::ContentArea          ScrolledContainer::d_contentAreaProperty;
ScrolledContainerProperties::ChildExtentsArea     ScrolledContainer::d_childExtentsAreaProperty;

//----------------------------------------------------------------------------//
ScrolledContainer::ScrolledContainer(const String& type, const String& name) :
    Window(type, name),
    d_contentArea(0, 0, 0, 0),
    d_autosizePane(true)
{
    addScrolledContainerProperties();
}

//----------------------------------------------------------------------------//
ScrolledContainer::~ScrolledContainer(void)
{
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::isContentPaneAutoSized(void) const
{
    return d_autosizePane;
}

//----------------------------------------------------------------------------//
void ScrolledContainer::setContentPaneAutoSized(bool setting)
{
    if (d_autosizePane != setting)
    {
        d_autosizePane = setting;

        // Fire events
        WindowEventArgs args1(this);
        onAutoSizeSettingChanged(args1);
    }
}

//----------------------------------------------------------------------------//
const Rect& ScrolledContainer::getContentArea(void) const
{
    return d_contentArea;
}

//----------------------------------------------------------------------------//
void ScrolledContainer::setContentArea(const Rect& area)
{
    if (!d_autosizePane)
    {
        d_contentArea = area;

        // Fire event
        WindowEventArgs args(this);
        onContentChanged(args);
   }

}

//----------------------------------------------------------------------------//
Rect ScrolledContainer::getChildExtentsArea(void) const
{
    size_t childCount = getChildCount();

    // set up initial content area to match first child.
    if (childCount != 0)
    {
        Window* wnd = getChildAtIdx(0);
        Rect extents(wnd->getArea().asAbsolute(d_pixelSize));

        // control var starts at 1 since we already dealt with 0 above
        for (size_t i = 1; i < childCount; ++i)
        {
            wnd = getChildAtIdx(i);
            Rect area(wnd->getArea().asAbsolute(d_pixelSize));

            if (area.d_left < extents.d_left)
                extents.d_left = area.d_left;

            if (area.d_top < extents.d_top)
                extents.d_top = area.d_top;

            if (area.d_right > extents.d_right)
                extents.d_right = area.d_right;

            if (area.d_bottom > extents.d_bottom)
                extents.d_bottom = area.d_bottom;
        }

        return extents;
    }
    else
    {
        return Rect(0, 0, 0, 0);
    }
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onContentChanged(WindowEventArgs& e)
{
    if (d_autosizePane)
    {
        d_contentArea = getChildExtentsArea();
    }

    fireEvent(EventContentChanged, e, EventNamespace);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onAutoSizeSettingChanged(WindowEventArgs& e)
{
    fireEvent(EventAutoSizeSettingChanged, e, EventNamespace);

    if (d_autosizePane)
    {
        WindowEventArgs args(this);
        onContentChanged(args);
    }
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::handleChildSized(const EventArgs&)
{
    // Fire event that notifies that a child's area has changed.
    WindowEventArgs args(this);
    onContentChanged(args);
    return true;
}

//----------------------------------------------------------------------------//
bool ScrolledContainer::handleChildMoved(const EventArgs&)
{
    // Fire event that notifies that a child's area has changed.
    WindowEventArgs args(this);
    onContentChanged(args);
    return true;
}

//----------------------------------------------------------------------------//
Rect ScrolledContainer::getUnclippedInnerRect_impl(void) const
{
    // return the size of our content as our inner rect.
    return CoordConverter::windowToScreen(*this, d_contentArea);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onChildAdded(WindowEventArgs& e)
{
    Window::onChildAdded(e);

    // subscribe to some events on this child
    d_eventConnections.insert(std::make_pair(e.window,
        e.window->subscribeEvent(Window::EventSized,
            Event::Subscriber(&ScrolledContainer::handleChildSized, this))));
    d_eventConnections.insert(std::make_pair(e.window,
        e.window->subscribeEvent(Window::EventMoved,
            Event::Subscriber(&ScrolledContainer::handleChildMoved, this))));

    // force window to update what it thinks it's screen / pixel areas are.
    e.window->notifyScreenAreaChanged(false);

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onChildRemoved(WindowEventArgs& e)
{
    Window::onChildRemoved(e);

    // disconnect from events for this window.
    ConnectionTracker::iterator conn;
    while ((conn = d_eventConnections.find(e.window)) != d_eventConnections.end())
    {
        conn->second->disconnect();
        d_eventConnections.erase(conn);
    }

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::onParentSized(WindowEventArgs& e)
{
    Window::onParentSized(e);

    // perform notification.
    WindowEventArgs args(this);
    onContentChanged(args);
}

//----------------------------------------------------------------------------//
void ScrolledContainer::addScrolledContainerProperties(void)
{
    addProperty(&d_autoSizedProperty);
    addProperty(&d_contentAreaProperty);
    addProperty(&d_childExtentsAreaProperty);
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include <stdio.h>
#include <PCU.h>
#include "parma.h"
#include "parma_balancer.h"
#include "parma_step.h"
#include "parma_sides.h"
#include "parma_weights.h"
#include "parma_targets.h"
#include "parma_selector.h"
#include "parma_commons.h"
#include "parma_convert.h"

namespace {
  using parmaCommons::status;

  class GhostEdgeBalancer : public parma::Balancer {
    private:
      int sideTol;
    public:
      GhostEdgeBalancer(apf::Mesh* m, double f, int v)
        : Balancer(m, f, v, "ghostEdges")
      {
        parma::Sides* s = parma::makeVtxSides(mesh);
        sideTol = TO_INT(parma::avgSharedSides(s));
        delete s;
        if( !PCU_Comm_Self() && verbose )
          status("sideTol %d\n", sideTol);
      }
      bool runStep(apf::MeshTag* wtag, double tolerance) {
        parma::Sides* s = parma::makeVtxSides(mesh);
        double avgSides = parma::avgSharedSides(s);
        if( !PCU_Comm_Self() && verbose )
          status("avgSides %f\n", avgSides);

        parma::GhostWeights* gw =
          parma::makeElmGhostWeights(mesh, wtag, s);
        parma::Weights* edgeW = convertGhostToEntWeight(gw,1);
        parma::Weights* vtxW =convertGhostToEntWeight(gw,0);
        destroyGhostWeights(gw);

        double vtxImb, vtxAvg;
        parma::getImbalance(vtxW, vtxImb, vtxAvg);
        if( !PCU_Comm_Self() && verbose )
          status("vtx imbalance %.3f avg %.3f\n", vtxImb, vtxAvg);
        delete vtxW;

        double elmImb, elmAvg;
        parma::getImbalance(edgeW, elmImb, elmAvg);
        monitorUpdate(elmImb, iS, iA);
        monitorUpdate(avgSides, sS, sA);

        parma::Targets* t = parma::makeTargets(s, edgeW, factor);
        parma::Selector* sel = parma::makeElmSelector(mesh, wtag);
        parma::BalOrStall* stopper =
          new parma::BalOrStall(iA, sA, sideTol*.001, verbose);
        parma::Stepper b(mesh, factor, s, edgeW, t, sel, "elm", stopper);
        bool ret = b.step(tolerance, verbose);
        return ret;
      }
      int layers;
  };
}

apf::Balancer* Parma_MakeGhostEdgeDiffuser(apf::Mesh* m,
    double stepFactor, int verbosity) {
  return new GhostEdgeBalancer(m,stepFactor,verbosity);
}
<commit_msg>use vtx selector<commit_after>#include <stdio.h>
#include <PCU.h>
#include "parma.h"
#include "parma_balancer.h"
#include "parma_step.h"
#include "parma_sides.h"
#include "parma_weights.h"
#include "parma_targets.h"
#include "parma_selector.h"
#include "parma_commons.h"
#include "parma_convert.h"

namespace {
  using parmaCommons::status;

  class GhostEdgeBalancer : public parma::Balancer {
    private:
      int sideTol;
    public:
      GhostEdgeBalancer(apf::Mesh* m, double f, int v)
        : Balancer(m, f, v, "ghostEdges")
      {
        parma::Sides* s = parma::makeVtxSides(mesh);
        sideTol = TO_INT(parma::avgSharedSides(s));
        delete s;
        if( !PCU_Comm_Self() && verbose )
          status("sideTol %d\n", sideTol);
      }
      bool runStep(apf::MeshTag* wtag, double tolerance) {
        parma::Sides* s = parma::makeVtxSides(mesh);
        double avgSides = parma::avgSharedSides(s);
        if( !PCU_Comm_Self() && verbose )
          status("avgSides %f\n", avgSides);

        parma::GhostWeights* gw =
          parma::makeElmGhostWeights(mesh, wtag, s);
        parma::Weights* edgeW = convertGhostToEntWeight(gw,1);
        parma::Weights* vtxW =convertGhostToEntWeight(gw,0);
        destroyGhostWeights(gw);

        double vtxImb, vtxAvg;
        parma::getImbalance(vtxW, vtxImb, vtxAvg);
        if( !PCU_Comm_Self() && verbose )
          status("vtx imbalance %.3f avg %.3f\n", vtxImb, vtxAvg);
        delete vtxW;

        double elmImb, elmAvg;
        parma::getImbalance(edgeW, elmImb, elmAvg);
        monitorUpdate(elmImb, iS, iA);
        monitorUpdate(avgSides, sS, sA);

        parma::Targets* t = parma::makeTargets(s, edgeW, factor);
        parma::Selector* sel = parma::makeVtxSelector(mesh, wtag);
        parma::BalOrStall* stopper =
          new parma::BalOrStall(iA, sA, sideTol*.001, verbose);
        parma::Stepper b(mesh, factor, s, edgeW, t, sel, "edge", stopper);
        bool ret = b.step(tolerance, verbose);
        return ret;
      }
      int layers;
  };
}

apf::Balancer* Parma_MakeGhostEdgeDiffuser(apf::Mesh* m,
    double stepFactor, int verbosity) {
  return new GhostEdgeBalancer(m,stepFactor,verbosity);
}
<|endoftext|>


<commit_before><commit_msg>minor formating fix<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 200000;
int fillv[4 * maxn];
int tsum[4 * maxn];

void push(int node, int left, int right) {
	if (fillv[node] == -1)
		return;
	tsum[node] = fillv[node] * (right - left + 1);
	if (left < right) {
		fillv[node * 2] = fillv[node];
		fillv[node * 2 + 1] = fillv[node];
	}
	fillv[node] = -1;
}

void pullUp(int node, int left, int right) {
	int mid = (left + right) >> 1;
	tsum[node] += (fillv[node * 2] != -1) ? fillv[node * 2] * (mid - left + 1) : tsum[node * 2];
	tsum[node] += (fillv[node * 2 + 1] != -1) ? fillv[node * 2 + 1] * (right - mid) : tsum[node * 2 + 1];
}

void add(int i, int value, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left == right) {
		tsum[node] += value;
		return;
	}
	int mid = (left + right) >> 1;
	if (i <= mid)
		add(i, value, node * 2, left, mid);
	else
		add(i, value, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
}

int sum(int a, int b, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left >= a && right <= b)
		return tsum[node];
	int mid = (left + right) >> 1;
	int res = 0;
	if (a <= mid) res += sum(a, b, node * 2, left, mid);
	if (b > mid) res += sum(a, b, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
	return res;
}

int get(int i) {
	return sum(i, i);
}

void set(int i, int value) {
	add(i, -get(i) + value);
}

void fill(int a, int b, int value, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left >= a && right <= b) {
		fillv[node] = value;
		return;
	}
	int mid = (left + right) >> 1;
	if (a <= mid) fill(a, b, value, node * 2, left, mid);
	if (b > mid) fill(a, b, value, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
}

int main() {
	fill(fillv, fillv + maxn, -1);
	set(0, 4);
	set(1, 5);
	add(1, 5);
	cout << (4 == get(0)) << endl;
	cout << (10 == get(1)) << endl;

	fill(0, 1, 1);
	cout << (1 == get(0)) << endl;
	cout << (1 == get(1)) << endl;
	cout << (0 == get(2)) << endl;
}
<commit_msg>update<commit_after>#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 200000;
int fillv[4 * maxn];
int tsum[4 * maxn];

void push(int node, int left, int right) {
	if (fillv[node] == -1)
		return;
	tsum[node] = fillv[node] * (right - left + 1);
	if (left < right) {
		fillv[node * 2] = fillv[node];
		fillv[node * 2 + 1] = fillv[node];
	}
	fillv[node] = -1;
}

void pullUp(int node, int left, int right) {
	int mid = (left + right) >> 1;
	tsum[node] = (fillv[node * 2] != -1) ? fillv[node * 2] * (mid - left + 1) : tsum[node * 2];
	tsum[node] += (fillv[node * 2 + 1] != -1) ? fillv[node * 2 + 1] * (right - mid) : tsum[node * 2 + 1];
}

void add(int i, int value, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left == right) {
		tsum[node] += value;
		return;
	}
	int mid = (left + right) >> 1;
	if (i <= mid)
		add(i, value, node * 2, left, mid);
	else
		add(i, value, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
}

int sum(int a, int b, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left >= a && right <= b)
		return tsum[node];
	int mid = (left + right) >> 1;
	int res = 0;
	if (a <= mid) res += sum(a, b, node * 2, left, mid);
	if (b > mid) res += sum(a, b, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
	return res;
}

int get(int i) {
	return sum(i, i);
}

void set(int i, int value) {
	add(i, -get(i) + value);
}

void fill(int a, int b, int value, int node = 1, int left = 0, int right = maxn - 1) {
	push(node, left, right);
	if (left >= a && right <= b) {
		fillv[node] = value;
		return;
	}
	int mid = (left + right) >> 1;
	if (a <= mid) fill(a, b, value, node * 2, left, mid);
	if (b > mid) fill(a, b, value, node * 2 + 1, mid + 1, right);
	pullUp(node, left, right);
}

int main() {
	fill(fillv, fillv + maxn, -1);
	set(0, 4);
	set(1, 5);
	add(1, 5);
	cout << (4 == get(0)) << endl;
	cout << (10 == get(1)) << endl;

	fill(0, 1, 1);
	cout << (1 == get(0)) << endl;
	cout << (1 == get(1)) << endl;
	cout << (0 == get(2)) << endl;
}
<|endoftext|>


<commit_before>//===-- Completion.cpp - Completion engine for swift immediate mode -------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This module provides completions to the immediate mode environment.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-completion"

#include "Completion.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Sema/Lookup.h"

using namespace swift;

static bool isIdentifier(char c) {
  return isalnum(c) || c == '_';
}

struct CompletionContext {
  enum class Kind {
    Invalid,
    Unqualified,
    Qualified
  } Kind;

  union {
    struct {
      DeclContext *dc;
      SourceLoc loc;
    } Unqualified;
    struct {
      TypeBase *baseTy;
    } Qualified;
  };

  CompletionContext(const CompletionContext &) = default;
  CompletionContext(CompletionContext &&) = default;
  CompletionContext &operator=(const CompletionContext &) = default;
  CompletionContext &operator=(CompletionContext &&) = default;

  CompletionContext() : Kind(Kind::Invalid) {}

  CompletionContext(DeclContext *dc, SourceLoc loc)
    : Kind(Kind::Unqualified), Unqualified{dc, loc} {
  }

  CompletionContext(Type baseTy)
    : Kind(Kind::Qualified), Qualified{baseTy.getPointer()} {
  }

  explicit operator bool() { return Kind != Kind::Invalid; }

  DeclContext *getDeclContext() const {
    assert(Kind == Kind::Unqualified);
    return Unqualified.dc;
  }
  SourceLoc getLoc() const {
    assert(Kind == Kind::Unqualified);
    return Unqualified.loc;
  }

  Type getBaseType() const {
    assert(Kind == Kind::Qualified);
    return Qualified.baseTy;
  }
};

static SourceLoc getTUEndLoc(TranslationUnit *TU) {
  return TU->Decls.empty()
    ? SourceLoc()
    : TU->Decls.back()->getSourceRange().End;
}

static void findBalancedBracket(char const *begin,
                                char const *&p,
                                char open,
                                char close) {
  unsigned depth = 1;
  if (p == begin) {
    --p;
    return;
  }
  do {
    --p;
    if (*p == close)
      ++depth;
    else if (*p == open)
      --depth;
  } while (depth != 0 && p > begin);

  --p;
}

static CompletionContext getCompletionContextFromDotExpression(
                                                           TranslationUnit *TU,
                                                           DeclContext *dc,
                                                           StringRef expr) {
  char const *begin = expr.begin(), *p = expr.end()-1, *end = expr.end();

  // Walk backward through identifier '.' identifier '.' ...
  while (true) {
    while (p >= begin && isspace(*p))
      --p;
    if (p < begin)
      break;

    bool requireIdentifier = true;
    if (*p == ')') {
      findBalancedBracket(begin, p, '(', ')');
      requireIdentifier = false;
    } else if (*p == ']') {
      findBalancedBracket(begin, p, '[', ']');
      requireIdentifier = false;
    } else if (*p == '>') {
      findBalancedBracket(begin, p, '<', '>');
      requireIdentifier = true;
    }

    while (p >= begin && isspace(*p))
      --p;
    if (p < begin)
      break;
    if (requireIdentifier && !isIdentifier(*p))
      break;

    while (p >= begin && isIdentifier(*p)) {
      --p;
    }

    while (p >= begin && isspace(*p))
      --p;
    if (p < begin || *p != '.')
      break;
    --p;
  }
  ++p;

  // Try to parse and typecheck the thing we found as an expression.
  StringRef exprPart = StringRef(p, end - p);
  DEBUG(llvm::dbgs() << "\ncompletion context string: " << exprPart << "\n");

  Expr *parsedExpr = parseCompletionContextExpr(TU, exprPart);

  // If we couldn't parse, give up.
  if (!parsedExpr)
    return CompletionContext();

  DEBUG(llvm::dbgs() << "\nparsed:\n";
        parsedExpr->print(llvm::dbgs());
        llvm::dbgs() << "\n");

  // Try to typecheck the expression.
  if (!typeCheckCompletionContextExpr(TU, parsedExpr))
    return CompletionContext();

  DEBUG(llvm::dbgs() << "\ntypechecked:\n";
        parsedExpr->print(llvm::dbgs());
        llvm::dbgs() << "\n");

  // Use the type as the context for qualified lookup.
  return CompletionContext(parsedExpr->getType());
}

/// Determine the DeclContext, lookup kind, and starting prefix in which to
/// perform a completion given an initial DeclContext and user-entered string.
static CompletionContext getCompletionContext(DeclContext *dc,
                                              StringRef &prefix) {
  // Find the TranslationUnit.
  DeclContext *tuDC = dc;
  while (!isa<TranslationUnit>(tuDC))
    tuDC = dc->getParent();
  TranslationUnit *TU = cast<TranslationUnit>(tuDC);

  SourceLoc tuEndLoc = getTUEndLoc(TU);

  if (prefix.empty())
    return CompletionContext(dc, tuEndLoc);

  if (isIdentifier(prefix.back())) {
    // If the character preceding us looks like a named identifier character,
    // walk backward to find as much of a name as we can.
    char const *p = prefix.end(), *end = p, *begin = prefix.begin();

    for (; p != begin; --p) {
      if (!isIdentifier(*(p-1))) {
        prefix = StringRef(p, end - p);
        break;
      }
    }

    // See if we were preceded by a dot.
    while (p >= begin && isspace(*--p));

    if (p >= begin && *p == '.') {
      // Try to figure out a qualified lookup context from the expression
      // preceding the dot.
      return getCompletionContextFromDotExpression(TU, dc,
                                                   StringRef(begin, p - begin));
    }

    // If there was no dot, do unqualified completion on the name.
    return CompletionContext(dc, tuEndLoc);
  } else if (prefix.back() == '.') {
    // Try to figure out a qualified lookup context from the expression
    // preceding the dot.
    StringRef beforeDot = prefix.slice(0, prefix.size() - 1);
    prefix = StringRef();
    return getCompletionContextFromDotExpression(TU, dc, beforeDot);
  } else if (Identifier::isOperatorChar(prefix.back())) {
    // If the character preceding us looks like an operator character,
    // walk backward to find as much of an operator name as we can.
    for (char const *p = prefix.end(), *end = p, *begin = prefix.begin();
         p != begin;
         --p) {
      if (!Identifier::isOperatorChar(*(p-1))) {
        prefix = StringRef(p, end - p);
        return CompletionContext(dc, tuEndLoc);
      }
    }

    // Operators only appear unqualified.
    return CompletionContext(dc, tuEndLoc);
  }

  // Complete everything at the top level.
  prefix = StringRef();
  return CompletionContext(dc, tuEndLoc);
}

/// Build completions by doing visible decl lookup from a context.
class CompletionLookup : swift::VisibleDeclConsumer,
                         clang::VisibleDeclConsumer
{
public:
  CompletionContext Context;
  llvm::StringRef Prefix;
  llvm::StringSet<> Results;
  Optional<StringRef> Root;

  void updateRoot(StringRef S) {
    if (!Root) {
      Root = S;
      return;
    }

    size_t len = 0;
    for (char const *r = Root->begin(), *s = S.begin();
         r != Root->end() && s != S.end();
         ++r, ++s) {
      if (*r == *s)
        ++len;
      else
        break;
    }
    Root = StringRef(Root->data(), len);
  }

  bool shouldCompleteDecl(ValueDecl *vd) {
    // Don't complete nameless values.
    if (vd->getName().empty())
      return false;

    // Don't complete constructors, destructors, or subscripts, since references
    // to them can't be spelled.
    // FIXME: except for super.constructor!
    if (isa<ConstructorDecl>(vd))
      return false;
    if (isa<DestructorDecl>(vd))
      return false;
    if (isa<SubscriptDecl>(vd))
      return false;

    // Don't complete class methods of instances.
    if (Context.Kind == CompletionContext::Kind::Qualified)
      if (auto *fd = dyn_cast<FuncDecl>(vd))
        if (fd->isStatic() && !Context.getBaseType()->is<MetaTypeType>())
          return false;

    return true;
  }

  // Implement swift::VisibleDeclConsumer
  void foundDecl(ValueDecl *vd) override {
    if (!shouldCompleteDecl(vd))
      return;
    StringRef name = vd->getName().get();
    if (!name.startswith(Prefix))
      return;

    if (Results.insert(name))
      updateRoot(name);
  }

  // Implement clang::VisibleDeclConsumer
  void FoundDecl(clang::NamedDecl *ND, clang::NamedDecl *Hiding,
                 clang::DeclContext *Ctx,
                 bool InBaseClass) override {
    StringRef name = ND->getName();
    if (!name.startswith(Prefix))
      return;

    if (Results.insert(name))
      updateRoot(name);
  }

  CompletionLookup(CompletionContext context, StringRef prefix)
    : Context(context), Prefix(prefix)
  {
    assert(context && "invalid completion lookup context!");

    if (context.Kind == CompletionContext::Kind::Unqualified) {
      lookupVisibleDecls(*this, context.getDeclContext(), context.getLoc());

      // TODO: Integrate Clang LookupVisibleDecls with Swift LookupVisibleDecls.
      // Doing so now makes REPL interaction too slow.

      ClangImporter &clangImporter
        = static_cast<ClangImporter&>(
                  context.getDeclContext()->getASTContext().getModuleLoader());
      clangImporter.lookupVisibleDecls(*this);
    } else
      lookupVisibleDecls(*this, context.getBaseType());
  }
};

StringRef Completions::allocateCopy(StringRef s) {
  size_t size = s.size();
  char *copy = static_cast<char*>(strings->Allocate(size + 1, 1));
  memcpy(copy, s.data(), size);
  copy[size] = '\0';
  return StringRef(copy, size);
}

Completions::Completions(DeclContext *dc, StringRef prefix)
  : strings(new llvm::BumpPtrAllocator()),
    enteredLength(0),
    rootLength(0),
    currentStem((size_t)-1)
{
  Type lookupType;
  CompletionContext context = getCompletionContext(dc, prefix);
  enteredLength = prefix.size();

  if (!context) {
    rootLength = 0;
    state = CompletionState::Empty;
    return;
  }

  CompletionLookup lookup(context, prefix);

  if (lookup.Results.empty()) {
    rootLength = 0;
    state = CompletionState::Empty;
    return;
  }

  rootLength = lookup.Root->size();

  assert(rootLength >= enteredLength && "completions don't match prefix?!");
  for (auto &c : lookup.Results) {
    completions.push_back(allocateCopy(c.getKey()));
  }
  std::sort(completions.begin(), completions.end(),
            [](StringRef a, StringRef b) { return a < b; });

  if (lookup.Results.size() == 1) {
    state = CompletionState::Unique;
    return;
  }
  state = CompletionState::CompletedRoot;
  return;
}

StringRef Completions::getRoot() const {
  if (completions.empty())
    return StringRef();
  return StringRef(completions[0].data() + enteredLength,
                   rootLength - enteredLength);
}

StringRef Completions::getPreviousStem() const {
  if (currentStem == (size_t)-1 || completions.empty())
    return StringRef();
  StringRef s = completions[currentStem];
  return StringRef(s.data() + rootLength, s.size() - rootLength);
}

StringRef Completions::getNextStem() {
  if (completions.empty())
    return StringRef();
  currentStem += 1;
  if (currentStem >= completions.size())
    currentStem = 0;
  StringRef s = completions[currentStem];
  return StringRef(s.data() + rootLength, s.size() - rootLength);
}

void Completions::reset() {
  if (isValid()) {
    state = CompletionState::Invalid;
    strings.reset();
    completions.clear();
  }
}<commit_msg>REPL: Poke 'metatype' into qualified completion sets.<commit_after>//===-- Completion.cpp - Completion engine for swift immediate mode -------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This module provides completions to the immediate mode environment.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-completion"

#include "Completion.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Sema/Lookup.h"

using namespace swift;

static bool isIdentifier(char c) {
  return isalnum(c) || c == '_';
}

struct CompletionContext {
  enum class Kind {
    Invalid,
    Unqualified,
    Qualified
  } Kind;

  union {
    struct {
      DeclContext *dc;
      SourceLoc loc;
    } Unqualified;
    struct {
      TypeBase *baseTy;
    } Qualified;
  };

  CompletionContext(const CompletionContext &) = default;
  CompletionContext(CompletionContext &&) = default;
  CompletionContext &operator=(const CompletionContext &) = default;
  CompletionContext &operator=(CompletionContext &&) = default;

  CompletionContext() : Kind(Kind::Invalid) {}

  CompletionContext(DeclContext *dc, SourceLoc loc)
    : Kind(Kind::Unqualified), Unqualified{dc, loc} {
  }

  CompletionContext(Type baseTy)
    : Kind(Kind::Qualified), Qualified{baseTy.getPointer()} {
  }

  explicit operator bool() { return Kind != Kind::Invalid; }

  DeclContext *getDeclContext() const {
    assert(Kind == Kind::Unqualified);
    return Unqualified.dc;
  }
  SourceLoc getLoc() const {
    assert(Kind == Kind::Unqualified);
    return Unqualified.loc;
  }

  Type getBaseType() const {
    assert(Kind == Kind::Qualified);
    return Qualified.baseTy;
  }
};

static SourceLoc getTUEndLoc(TranslationUnit *TU) {
  return TU->Decls.empty()
    ? SourceLoc()
    : TU->Decls.back()->getSourceRange().End;
}

static void findBalancedBracket(char const *begin,
                                char const *&p,
                                char open,
                                char close) {
  unsigned depth = 1;
  if (p == begin) {
    --p;
    return;
  }
  do {
    --p;
    if (*p == close)
      ++depth;
    else if (*p == open)
      --depth;
  } while (depth != 0 && p > begin);

  --p;
}

static CompletionContext getCompletionContextFromDotExpression(
                                                           TranslationUnit *TU,
                                                           DeclContext *dc,
                                                           StringRef expr) {
  char const *begin = expr.begin(), *p = expr.end()-1, *end = expr.end();

  // Walk backward through identifier '.' identifier '.' ...
  while (true) {
    while (p >= begin && isspace(*p))
      --p;
    if (p < begin)
      break;

    bool requireIdentifier = true;
    if (*p == ')') {
      findBalancedBracket(begin, p, '(', ')');
      requireIdentifier = false;
    } else if (*p == ']') {
      findBalancedBracket(begin, p, '[', ']');
      requireIdentifier = false;
    } else if (*p == '>') {
      findBalancedBracket(begin, p, '<', '>');
      requireIdentifier = true;
    }

    while (p >= begin && isspace(*p))
      --p;
    if (p < begin)
      break;
    if (requireIdentifier && !isIdentifier(*p))
      break;

    while (p >= begin && isIdentifier(*p)) {
      --p;
    }

    while (p >= begin && isspace(*p))
      --p;
    if (p < begin || *p != '.')
      break;
    --p;
  }
  ++p;

  // Try to parse and typecheck the thing we found as an expression.
  StringRef exprPart = StringRef(p, end - p);
  DEBUG(llvm::dbgs() << "\ncompletion context string: " << exprPart << "\n");

  Expr *parsedExpr = parseCompletionContextExpr(TU, exprPart);

  // If we couldn't parse, give up.
  if (!parsedExpr)
    return CompletionContext();

  DEBUG(llvm::dbgs() << "\nparsed:\n";
        parsedExpr->print(llvm::dbgs());
        llvm::dbgs() << "\n");

  // Try to typecheck the expression.
  if (!typeCheckCompletionContextExpr(TU, parsedExpr))
    return CompletionContext();

  DEBUG(llvm::dbgs() << "\ntypechecked:\n";
        parsedExpr->print(llvm::dbgs());
        llvm::dbgs() << "\n");

  // Use the type as the context for qualified lookup.
  return CompletionContext(parsedExpr->getType());
}

/// Determine the DeclContext, lookup kind, and starting prefix in which to
/// perform a completion given an initial DeclContext and user-entered string.
static CompletionContext getCompletionContext(DeclContext *dc,
                                              StringRef &prefix) {
  // Find the TranslationUnit.
  DeclContext *tuDC = dc;
  while (!isa<TranslationUnit>(tuDC))
    tuDC = dc->getParent();
  TranslationUnit *TU = cast<TranslationUnit>(tuDC);

  SourceLoc tuEndLoc = getTUEndLoc(TU);

  if (prefix.empty())
    return CompletionContext(dc, tuEndLoc);

  if (isIdentifier(prefix.back())) {
    // If the character preceding us looks like a named identifier character,
    // walk backward to find as much of a name as we can.
    char const *p = prefix.end(), *end = p, *begin = prefix.begin();

    for (; p != begin; --p) {
      if (!isIdentifier(*(p-1))) {
        prefix = StringRef(p, end - p);
        break;
      }
    }

    // See if we were preceded by a dot.
    while (p >= begin && isspace(*--p));

    if (p >= begin && *p == '.') {
      // Try to figure out a qualified lookup context from the expression
      // preceding the dot.
      return getCompletionContextFromDotExpression(TU, dc,
                                                   StringRef(begin, p - begin));
    }

    // If there was no dot, do unqualified completion on the name.
    return CompletionContext(dc, tuEndLoc);
  } else if (prefix.back() == '.') {
    // Try to figure out a qualified lookup context from the expression
    // preceding the dot.
    StringRef beforeDot = prefix.slice(0, prefix.size() - 1);
    prefix = StringRef();
    return getCompletionContextFromDotExpression(TU, dc, beforeDot);
  } else if (Identifier::isOperatorChar(prefix.back())) {
    // If the character preceding us looks like an operator character,
    // walk backward to find as much of an operator name as we can.
    for (char const *p = prefix.end(), *end = p, *begin = prefix.begin();
         p != begin;
         --p) {
      if (!Identifier::isOperatorChar(*(p-1))) {
        prefix = StringRef(p, end - p);
        return CompletionContext(dc, tuEndLoc);
      }
    }

    // Operators only appear unqualified.
    return CompletionContext(dc, tuEndLoc);
  }

  // Complete everything at the top level.
  prefix = StringRef();
  return CompletionContext(dc, tuEndLoc);
}

/// Build completions by doing visible decl lookup from a context.
class CompletionLookup : swift::VisibleDeclConsumer,
                         clang::VisibleDeclConsumer
{
public:
  CompletionContext Context;
  llvm::StringRef Prefix;
  llvm::StringSet<> Results;
  Optional<StringRef> Root;

  void updateRoot(StringRef S) {
    if (!Root) {
      Root = S;
      return;
    }

    size_t len = 0;
    for (char const *r = Root->begin(), *s = S.begin();
         r != Root->end() && s != S.end();
         ++r, ++s) {
      if (*r == *s)
        ++len;
      else
        break;
    }
    Root = StringRef(Root->data(), len);
  }

  bool shouldCompleteDecl(ValueDecl *vd) {
    // Don't complete nameless values.
    if (vd->getName().empty())
      return false;

    // Don't complete constructors, destructors, or subscripts, since references
    // to them can't be spelled.
    // FIXME: except for super.constructor!
    if (isa<ConstructorDecl>(vd))
      return false;
    if (isa<DestructorDecl>(vd))
      return false;
    if (isa<SubscriptDecl>(vd))
      return false;

    // Don't complete class methods of instances.
    if (Context.Kind == CompletionContext::Kind::Qualified)
      if (auto *fd = dyn_cast<FuncDecl>(vd))
        if (fd->isStatic() && !Context.getBaseType()->is<MetaTypeType>())
          return false;

    return true;
  }

  void addCompletionString(llvm::StringRef name) {
    if (!name.startswith(Prefix))
      return;

    if (Results.insert(name))
      updateRoot(name);
  }

  // Implement swift::VisibleDeclConsumer
  void foundDecl(ValueDecl *vd) override {
    if (!shouldCompleteDecl(vd))
      return;
    StringRef name = vd->getName().get();

    addCompletionString(name);
  }

  // Implement clang::VisibleDeclConsumer
  void FoundDecl(clang::NamedDecl *ND, clang::NamedDecl *Hiding,
                 clang::DeclContext *Ctx,
                 bool InBaseClass) override {
    StringRef name = ND->getName();

    addCompletionString(name);
  }

  CompletionLookup(CompletionContext context, StringRef prefix)
    : Context(context), Prefix(prefix)
  {
    assert(context && "invalid completion lookup context!");

    if (context.Kind == CompletionContext::Kind::Unqualified) {
      lookupVisibleDecls(*this, context.getDeclContext(), context.getLoc());

      // TODO: Integrate Clang LookupVisibleDecls with Swift LookupVisibleDecls.
      // Doing so now makes REPL interaction too slow.

      ClangImporter &clangImporter
        = static_cast<ClangImporter&>(
                  context.getDeclContext()->getASTContext().getModuleLoader());
      clangImporter.lookupVisibleDecls(*this);
    } else {
      lookupVisibleDecls(*this, context.getBaseType());

      // Add the special qualified keyword 'metatype' so that, for example,
      // 'Int.metatype' can be completed.
      addCompletionString("metatype");
    }
  }
};

StringRef Completions::allocateCopy(StringRef s) {
  size_t size = s.size();
  char *copy = static_cast<char*>(strings->Allocate(size + 1, 1));
  memcpy(copy, s.data(), size);
  copy[size] = '\0';
  return StringRef(copy, size);
}

Completions::Completions(DeclContext *dc, StringRef prefix)
  : strings(new llvm::BumpPtrAllocator()),
    enteredLength(0),
    rootLength(0),
    currentStem((size_t)-1)
{
  Type lookupType;
  CompletionContext context = getCompletionContext(dc, prefix);
  enteredLength = prefix.size();

  if (!context) {
    rootLength = 0;
    state = CompletionState::Empty;
    return;
  }

  CompletionLookup lookup(context, prefix);

  if (lookup.Results.empty()) {
    rootLength = 0;
    state = CompletionState::Empty;
    return;
  }

  rootLength = lookup.Root->size();

  assert(rootLength >= enteredLength && "completions don't match prefix?!");
  for (auto &c : lookup.Results) {
    completions.push_back(allocateCopy(c.getKey()));
  }
  std::sort(completions.begin(), completions.end(),
            [](StringRef a, StringRef b) { return a < b; });

  if (lookup.Results.size() == 1) {
    state = CompletionState::Unique;
    return;
  }
  state = CompletionState::CompletedRoot;
  return;
}

StringRef Completions::getRoot() const {
  if (completions.empty())
    return StringRef();
  return StringRef(completions[0].data() + enteredLength,
                   rootLength - enteredLength);
}

StringRef Completions::getPreviousStem() const {
  if (currentStem == (size_t)-1 || completions.empty())
    return StringRef();
  StringRef s = completions[currentStem];
  return StringRef(s.data() + rootLength, s.size() - rootLength);
}

StringRef Completions::getNextStem() {
  if (completions.empty())
    return StringRef();
  currentStem += 1;
  if (currentStem >= completions.size())
    currentStem = 0;
  StringRef s = completions[currentStem];
  return StringRef(s.data() + rootLength, s.size() - rootLength);
}

void Completions::reset() {
  if (isValid()) {
    state = CompletionState::Invalid;
    strings.reset();
    completions.clear();
  }
}<|endoftext|>