From 2de0e86e96b24ef5b5fa6c8b846f58c26caa820e Mon Sep 17 00:00:00 2001 From: peterychang Date: Thu, 2 Jan 2020 14:56:06 -0500 Subject: [PATCH 1/3] deprecate last and pop, implement insert, erase, capacity --- python/pylibvw.cc | 12 ++-- vowpalwabbit/autolink.cc | 2 +- vowpalwabbit/comp_io.cc | 2 +- vowpalwabbit/conditional_contextual_bandit.cc | 8 +-- vowpalwabbit/csoaa.cc | 4 +- vowpalwabbit/ect.cc | 2 +- vowpalwabbit/example.h | 2 +- vowpalwabbit/ezexample.h | 2 +- vowpalwabbit/interact.cc | 18 +++--- vowpalwabbit/io_buf.cc | 2 +- vowpalwabbit/io_buf.h | 5 +- vowpalwabbit/kernel_svm.cc | 8 +-- vowpalwabbit/label_dictionary.cc | 4 +- vowpalwabbit/lda_core.cc | 4 +- vowpalwabbit/memory_tree.cc | 4 +- vowpalwabbit/mwt.cc | 3 +- vowpalwabbit/nn.cc | 2 +- vowpalwabbit/parse_example.cc | 9 +-- vowpalwabbit/parser.cc | 13 ++-- vowpalwabbit/recall_tree.cc | 2 +- vowpalwabbit/search.cc | 14 ++--- vowpalwabbit/search_dep_parser.cc | 40 ++++++------- vowpalwabbit/search_entityrelationtask.cc | 4 +- vowpalwabbit/search_graph.cc | 2 +- vowpalwabbit/slim/src/vw_slim_predict.cc | 4 +- vowpalwabbit/v_array.h | 59 +++++++++++++++---- vowpalwabbit/vwdll.cpp | 2 +- 27 files changed, 138 insertions(+), 95 deletions(-) diff --git a/python/pylibvw.cc b/python/pylibvw.cc index 6c4f09dcbd3..97fed70ca5f 100644 --- a/python/pylibvw.cc +++ b/python/pylibvw.cc @@ -381,11 +381,12 @@ void ex_push_dictionary(example_ptr ec, vw_ptr vw, py::dict& dict) bool ex_pop_feature(example_ptr ec, unsigned char ns) { if (ec->feature_space[ns].size() == 0) return false; - float val = ec->feature_space[ns].values.pop(); + float val = ec->feature_space[ns].values.back(); + ec->feature_space[ns].values.pop_back(); if (ec->feature_space[ns].indicies.size()> 0) - ec->feature_space[ns].indicies.pop(); + ec->feature_space[ns].indicies.pop_back(); if (ec->feature_space[ns].space_names.size()> 0) - ec->feature_space[ns].space_names.pop(); + ec->feature_space[ns].space_names.pop_back(); ec->num_features--; ec->feature_space[ns].sum_feat_sq -= val * val; ec->total_sum_feat_sq -= val * val; @@ -401,7 +402,8 @@ void ex_erase_namespace(example_ptr ec, unsigned char ns) bool ex_pop_namespace(example_ptr ec) { if (ec->indices.size() == 0) return false; - unsigned char ns = ec->indices.pop(); + unsigned char ns = ec->indices.back(); + ec->indices.pop_back(); ex_erase_namespace(ec, ns); return true; } @@ -446,7 +448,7 @@ void unsetup_example(vw_ptr vwP, example_ptr ae) if (hit_constant >= 0) { for (size_t i=hit_constant; iindices[i] = ae->indices[i+1]; - ae->indices.pop(); + ae->indices.pop_back(); } } diff --git a/vowpalwabbit/autolink.cc b/vowpalwabbit/autolink.cc index 988c34933dd..7c7734334f6 100644 --- a/vowpalwabbit/autolink.cc +++ b/vowpalwabbit/autolink.cc @@ -74,7 +74,7 @@ void VW::autolink::reset_example(example& ec) features& fs = ec.feature_space[autolink_namespace]; ec.total_sum_feat_sq -= fs.sum_feat_sq; fs.clear(); - ec.indices.pop(); + ec.indices.pop_back(); } template diff --git a/vowpalwabbit/comp_io.cc b/vowpalwabbit/comp_io.cc index cd784d0180f..f19e5dae6a1 100644 --- a/vowpalwabbit/comp_io.cc +++ b/vowpalwabbit/comp_io.cc @@ -84,7 +84,7 @@ bool comp_io_buf::close_file() gzclose(gz_files.back()); gz_files.pop_back(); if (!files.empty()) - files.pop(); + files.pop_back(); return true; } return false; diff --git a/vowpalwabbit/conditional_contextual_bandit.cc b/vowpalwabbit/conditional_contextual_bandit.cc index a040a38a739..93fbb0aef0d 100644 --- a/vowpalwabbit/conditional_contextual_bandit.cc +++ b/vowpalwabbit/conditional_contextual_bandit.cc @@ -250,13 +250,13 @@ void inject_slot_id(ccb& data, example* shared, size_t id) template void remove_slot_id(example* shared) { - shared->feature_space[ccb_id_namespace].indicies.pop(); - shared->feature_space[ccb_id_namespace].values.pop(); - shared->indices.pop(); + shared->feature_space[ccb_id_namespace].indicies.pop_back(); + shared->feature_space[ccb_id_namespace].values.pop_back(); + shared->indices.pop_back(); if (audit) { - shared->feature_space[ccb_id_namespace].space_names.pop(); + shared->feature_space[ccb_id_namespace].space_names.pop_back(); } } diff --git a/vowpalwabbit/csoaa.cc b/vowpalwabbit/csoaa.cc index 22ffafeec8f..892089b401c 100644 --- a/vowpalwabbit/csoaa.cc +++ b/vowpalwabbit/csoaa.cc @@ -228,7 +228,7 @@ void unsubtract_example(example* ec) return; } - if (ec->indices.last() != wap_ldf_namespace) + if (ec->indices.back() != wap_ldf_namespace) { std::cerr << "internal error (bug): trying to unsubtract_example, but either it wasn't added, or something was added " @@ -241,7 +241,7 @@ void unsubtract_example(example* ec) ec->num_features -= fs.size(); ec->total_sum_feat_sq -= fs.sum_feat_sq; fs.clear(); - ec->indices.decr(); + ec->indices.pop_back(); } void make_single_prediction(ldf& data, single_learner& base, example& ec) diff --git a/vowpalwabbit/ect.cc b/vowpalwabbit/ect.cc index cbfc786b36a..af2a061c2ea 100644 --- a/vowpalwabbit/ect.cc +++ b/vowpalwabbit/ect.cc @@ -174,7 +174,7 @@ size_t create_circuit(ect& e, uint64_t max_label, uint64_t eliminations) e.directions[direction_index].loser = 0; } if (tournaments[t].size() % 2 == 1) - new_tournaments[t].push_back(tournaments[t].last()); + new_tournaments[t].push_back(tournaments[t].back()); } e.all_levels.push_back(new_tournaments); level++; diff --git a/vowpalwabbit/example.h b/vowpalwabbit/example.h index b1ea65c8872..02e787e70e4 100644 --- a/vowpalwabbit/example.h +++ b/vowpalwabbit/example.h @@ -103,7 +103,7 @@ inline int example_is_newline(example const& ec) { // if only index is constant namespace or no index if (!ec.tag.empty()) return false; - return ((ec.indices.empty()) || ((ec.indices.size() == 1) && (ec.indices.last() == constant_namespace))); + return ((ec.indices.empty()) || ((ec.indices.size() == 1) && (ec.indices.back() == constant_namespace))); } inline bool valid_ns(char c) { return !(c == '|' || c == ':'); } diff --git a/vowpalwabbit/ezexample.h b/vowpalwabbit/ezexample.h index 5e958a1cee7..e043385f50d 100644 --- a/vowpalwabbit/ezexample.h +++ b/vowpalwabbit/ezexample.h @@ -177,7 +177,7 @@ class ezexample current_seed = past_seeds.back(); past_seeds.pop_back(); - ec->indices.pop(); + ec->indices.pop_back(); example_changed_since_prediction = true; } } diff --git a/vowpalwabbit/interact.cc b/vowpalwabbit/interact.cc index 3d9786cf6e9..7812dbf612a 100644 --- a/vowpalwabbit/interact.cc +++ b/vowpalwabbit/interact.cc @@ -123,14 +123,13 @@ void predict_or_learn(interact& in, LEARNER::single_learner& base, example& ec) std::cout<< std::endl;*/ // remove 2nd namespace - int n2_i = -1; - for (size_t i = 0; i < ec.indices.size(); i++) + size_t n2_i = 0; + size_t indices_original_size = ec.indices.size(); + for (; n2_i < indices_original_size; ++n2_i) { - if (ec.indices[i] == in.n2) + if (ec.indices[n2_i] == in.n2) { - n2_i = (int)i; - memmove(&ec.indices[n2_i], &ec.indices[n2_i + 1], sizeof(unsigned char) * (ec.indices.size() - n2_i - 1)); - ec.indices.decr(); + ec.indices.erase(n2_i); break; } } @@ -139,10 +138,9 @@ void predict_or_learn(interact& in, LEARNER::single_learner& base, example& ec) if (is_learn) base.learn(ec); - // re-insert namespace into the right position - ec.indices.incr(); - memmove(&ec.indices[n2_i + 1], &ec.indices[n2_i], sizeof(unsigned char) * (ec.indices.size() - n2_i - 1)); - ec.indices[n2_i] = in.n2; + // re-insert namespace into the right position (if one was removed) + if (n2_i < indices_original_size) + ec.indices.insert(n2_i, in.n2); f1.deep_copy_from(in.feat_store); ec.total_sum_feat_sq = in.total_sum_feat_sq; diff --git a/vowpalwabbit/io_buf.cc b/vowpalwabbit/io_buf.cc index 4baf0829176..996e3c108c5 100644 --- a/vowpalwabbit/io_buf.cc +++ b/vowpalwabbit/io_buf.cc @@ -103,7 +103,7 @@ void io_buf::buf_write(char*& pointer, size_t n) flush(); else // Array is short, so increase size. { - space.resize(2 * (space.end_array - space.begin())); + space.resize(2 * space.capacity()); space.end() = space.begin(); head = space.begin(); } diff --git a/vowpalwabbit/io_buf.h b/vowpalwabbit/io_buf.h index 6cadafbf34d..5f1718a9bad 100644 --- a/vowpalwabbit/io_buf.h +++ b/vowpalwabbit/io_buf.h @@ -172,7 +172,7 @@ class io_buf if (space.end_array - space.end() == 0) { // reallocate to twice as much space size_t head_loc = head - space.begin(); - space.resize(2 * (space.end_array - space.begin())); + space.resize(2 * space.capacity()); head = space.begin() + head_loc; } // read more bytes from file up to the remaining allocated space @@ -204,7 +204,8 @@ class io_buf { if (!files.empty()) { - close_file_or_socket(files.pop()); + close_file_or_socket(files.back()); + files.pop_back(); return true; } return false; diff --git a/vowpalwabbit/kernel_svm.cc b/vowpalwabbit/kernel_svm.cc index fe396b2094c..f48fcebb491 100644 --- a/vowpalwabbit/kernel_svm.cc +++ b/vowpalwabbit/kernel_svm.cc @@ -523,9 +523,9 @@ int remove(svm_params& params, size_t svi) } svi_e->~svm_example(); free(svi_e); - model->support_vec.pop(); - model->alpha.pop(); - model->delta.pop(); + model->support_vec.pop_back(); + model->alpha.pop_back(); + model->delta.pop_back(); model->num_support--; // shift cache int alloc = 0; @@ -536,7 +536,7 @@ int remove(svm_params& params, size_t svi) if (svi < rowsize) { for (size_t i = svi; i < rowsize - 1; i++) e->krow[i] = e->krow[i + 1]; - e->krow.pop(); + e->krow.pop_back(); alloc -= 1; } } diff --git a/vowpalwabbit/label_dictionary.cc b/vowpalwabbit/label_dictionary.cc index 3eeeb79f01c..18c537db5e1 100644 --- a/vowpalwabbit/label_dictionary.cc +++ b/vowpalwabbit/label_dictionary.cc @@ -17,8 +17,8 @@ void del_example_namespace(example& ec, namespace_index ns, features& fs) features& del_target = ec.feature_space[(size_t)ns]; assert(del_target.size() >= fs.size()); assert(ec.indices.size() > 0); - if (ec.indices.last() == ns && ec.feature_space[(size_t)ns].size() == fs.size()) - ec.indices.pop(); + if (ec.indices.back() == ns && ec.feature_space[(size_t)ns].size() == fs.size()) + ec.indices.pop_back(); ec.total_sum_feat_sq -= fs.sum_feat_sq; ec.num_features -= fs.size(); del_target.truncate_to(del_target.size() - fs.size()); diff --git a/vowpalwabbit/lda_core.cc b/vowpalwabbit/lda_core.cc index e8ce93a625e..379a3ee6b60 100644 --- a/vowpalwabbit/lda_core.cc +++ b/vowpalwabbit/lda_core.cc @@ -909,7 +909,7 @@ void learn_batch(lda &l) eta = l.all->eta * l.powf((float)l.example_t, -l.all->power_t); minuseta = 1.0f - eta; eta *= l.lda_D / batch_size; - l.decay_levels.push_back(l.decay_levels.last() + log(minuseta)); + l.decay_levels.push_back(l.decay_levels.back() + log(minuseta)); l.digammas.clear(); float additional = (float)(l.all->length()) * l.lda_rho; @@ -1259,7 +1259,7 @@ void end_examples(lda &l, T &weights) for (typename T::iterator iter = weights.begin(); iter != weights.end(); ++iter) { float decay_component = - l.decay_levels.last() - l.decay_levels.end()[(int)(-1 - l.example_t + (&(*iter))[l.all->lda])]; + l.decay_levels.back() - l.decay_levels.end()[(int)(-1 - l.example_t + (&(*iter))[l.all->lda])]; float decay = fmin(1.f, correctedExp(decay_component)); weight *wp = &(*iter); diff --git a/vowpalwabbit/memory_tree.cc b/vowpalwabbit/memory_tree.cc index e186440431c..cbac129075f 100644 --- a/vowpalwabbit/memory_tree.cc +++ b/vowpalwabbit/memory_tree.cc @@ -33,14 +33,14 @@ void remove_at_index(v_array& array, uint32_t index) } if (index == array.size() - 1) { - array.pop(); + array.pop_back(); return; } for (size_t i = index + 1; i < array.size(); i++) { array[i - 1] = array[i]; } - array.pop(); + array.pop_back(); return; } diff --git a/vowpalwabbit/mwt.cc b/vowpalwabbit/mwt.cc index 3f6e2acd251..3ed93d5cd3b 100644 --- a/vowpalwabbit/mwt.cc +++ b/vowpalwabbit/mwt.cc @@ -130,7 +130,8 @@ void predict_or_learn(mwt& c, single_learner& base, example& ec) if (exclude || learn) while (!c.indices.empty()) { - unsigned char ns = c.indices.pop(); + unsigned char ns = c.indices.back(); + c.indices.pop_back(); std::swap(c.feature_space[ns], ec.feature_space[ns]); } diff --git a/vowpalwabbit/nn.cc b/vowpalwabbit/nn.cc index f32bb02d0ac..8be94b55e8b 100644 --- a/vowpalwabbit/nn.cc +++ b/vowpalwabbit/nn.cc @@ -320,7 +320,7 @@ void predict_or_learn_multi(nn& n, single_learner& base, example& ec) ec.total_sum_feat_sq -= tmp_sum_feat_sq; ec.feature_space[nn_output_namespace].sum_feat_sq = 0; std::swap(ec.feature_space[nn_output_namespace], save_nn_output_namespace); - ec.indices.pop(); + ec.indices.pop_back(); } else { diff --git a/vowpalwabbit/parse_example.cc b/vowpalwabbit/parse_example.cc index 4167795cb9c..965ec0d27f3 100644 --- a/vowpalwabbit/parse_example.cc +++ b/vowpalwabbit/parse_example.cc @@ -219,7 +219,7 @@ class TC_parser d = '.'; else d = '#'; - // if ((spelling.size() == 0) || (spelling.last() != d)) + // if ((spelling.size() == 0) || (spelling.back() != d)) _spelling.push_back(d); } @@ -444,10 +444,11 @@ void substring_to_example(vw* all, example* ae, VW::string_view example) std::vector tokenized; tokenize(' ', label_space, all->p->words); if (all->p->words.size() > 0 && - (all->p->words.last().end() == label_space.end() || - all->p->words.last().front() == '\'')) // The last field is a tag, so record and strip it off + (all->p->words.back().end() == label_space.end() || + all->p->words.back().front() == '\'')) // The last field is a tag, so record and strip it off { - VW::string_view tag = all->p->words.pop(); + VW::string_view tag = all->p->words.back(); + all->p->words.pop_back(); if (tag.front() == '\'') tag.remove_prefix(1); push_many(ae->tag, tag.begin(), tag.size()); diff --git a/vowpalwabbit/parser.cc b/vowpalwabbit/parser.cc index 1a2331986fe..0908fc4398f 100644 --- a/vowpalwabbit/parser.cc +++ b/vowpalwabbit/parser.cc @@ -141,7 +141,8 @@ void reset_source(vw& all, size_t numbits) input->close_file(); else { - int fd = input->files.pop(); + int fd = input->files.back(); + input->files.pop_back(); const auto& fps = all.final_prediction_sink; // If the current popped file is not in the list of final predictions sinks, close it. @@ -208,7 +209,7 @@ void finalize_source(parser* p) #else int f = fileno(stdin); #endif - while (!p->input->files.empty() && p->input->files.last() == f) p->input->files.pop(); + while (!p->input->files.empty() && p->input->files.back() == f) p->input->files.pop_back(); p->input->close_files(); delete p->input; @@ -586,9 +587,9 @@ void set_done(vw& all) void addgrams(vw& all, size_t ngram, size_t skip_gram, features& fs, size_t initial_length, v_array& gram_mask, size_t skips) { - if (ngram == 0 && gram_mask.last() < initial_length) + if (ngram == 0 && gram_mask.back() < initial_length) { - size_t last = initial_length - gram_mask.last(); + size_t last = initial_length - gram_mask.back(); for (size_t i = 0; i < last; i++) { uint64_t new_index = fs.indicies[i]; @@ -610,9 +611,9 @@ void addgrams(vw& all, size_t ngram, size_t skip_gram, features& fs, size_t init } if (ngram > 0) { - gram_mask.push_back(gram_mask.last() + 1 + skips); + gram_mask.push_back(gram_mask.back() + 1 + skips); addgrams(all, ngram - 1, skip_gram, fs, initial_length, gram_mask, 0); - gram_mask.pop(); + gram_mask.pop_back(); } if (skip_gram > 0 && ngram > 0) addgrams(all, ngram, skip_gram - 1, fs, initial_length, gram_mask, skips + 1); diff --git a/vowpalwabbit/recall_tree.cc b/vowpalwabbit/recall_tree.cc index 431ada1eea8..5eae74379a8 100644 --- a/vowpalwabbit/recall_tree.cc +++ b/vowpalwabbit/recall_tree.cc @@ -246,7 +246,7 @@ void remove_node_id_feature(recall_tree& /* b */, uint32_t /* cn */, example& ec { features& fs = ec.feature_space[node_id_namespace]; fs.clear(); - ec.indices.pop(); + ec.indices.pop_back(); } uint32_t oas_predict(recall_tree& b, single_learner& base, uint32_t cn, example& ec) diff --git a/vowpalwabbit/search.cc b/vowpalwabbit/search.cc index 5df4c56d98b..43c98d08395 100644 --- a/vowpalwabbit/search.cc +++ b/vowpalwabbit/search.cc @@ -617,7 +617,7 @@ void add_new_feature(search_private& priv, float val, uint64_t idx) uint64_t idx2 = ((idx & mask) >> ss) & mask; features& fs = priv.dat_new_feature_ec->feature_space[priv.dat_new_feature_namespace]; fs.push_back(val * priv.dat_new_feature_value, ((priv.dat_new_feature_idx + idx2) << ss)); - cdbg << "adding: " << fs.indicies.last() << ':' << fs.values.last() << endl; + cdbg << "adding: " << fs.indicies.back() << ':' << fs.values.back() << endl; if (priv.all->audit) { std::stringstream temp; @@ -628,17 +628,17 @@ void add_new_feature(search_private& priv, float val, uint64_t idx) void del_features_in_top_namespace(search_private& /* priv */, example& ec, size_t ns) { - if ((ec.indices.size() == 0) || (ec.indices.last() != ns)) + if ((ec.indices.size() == 0) || (ec.indices.back() != ns)) { return; // if (ec.indices.size() == 0) //{ THROW("internal error (bug): expecting top namespace to be '" << ns << "' but it was empty"); } // else //{ THROW("internal error (bug): expecting top namespace to be '" << ns << "' but it was " << - //(size_t)ec.indices.last()); } + //(size_t)ec.indices.back()); } } features& fs = ec.feature_space[ns]; - ec.indices.decr(); + ec.indices.pop_back(); ec.num_features -= fs.size(); ec.total_sum_feat_sq -= fs.sum_feat_sq; fs.clear(); @@ -895,7 +895,7 @@ void add_example_conditioning(search_private& priv, example& ec, size_t conditio void del_example_conditioning(search_private& priv, example& ec) { - if ((ec.indices.size() > 0) && (ec.indices.last() == conditioning_namespace)) + if ((ec.indices.size() > 0) && (ec.indices.back() == conditioning_namespace)) del_features_in_top_namespace(priv, ec, conditioning_namespace); } @@ -1080,7 +1080,7 @@ void allowed_actions_to_label(search_private& priv, size_t ec_cnt, const action* template void ensure_size(v_array& A, size_t sz) { - if ((size_t)(A.end_array - A.begin()) < sz) + if (A.capacity() < sz) A.resize(sz * 2 + 1); A.end() = A.begin() + sz; } @@ -3484,7 +3484,7 @@ action predictor::predict() : sch.predict(*ec, my_tag, orA, oracle_actions.size(), cOn, cNa, alA, numAlA, alAcosts, learner_id, weight); if (condition_on_names.size() > 0) - condition_on_names.pop(); // un-null-terminate + condition_on_names.pop_back(); // un-null-terminate return p; } } // namespace Search diff --git a/vowpalwabbit/search_dep_parser.cc b/vowpalwabbit/search_dep_parser.cc index d501100fb55..1976af51bea 100644 --- a/vowpalwabbit/search_dep_parser.cc +++ b/vowpalwabbit/search_dep_parser.cc @@ -162,7 +162,7 @@ size_t transition_hybrid(Search::search &sch, uint64_t a_id, uint32_t idx, uint3 } else if (a_id == REDUCE_RIGHT) { - uint32_t last = stack.last(); + uint32_t last = stack.back(); uint32_t hd = stack[stack.size() - 2]; heads[last] = hd; children[5][hd] = children[4][hd]; @@ -171,12 +171,12 @@ size_t transition_hybrid(Search::search &sch, uint64_t a_id, uint32_t idx, uint3 tags[last] = t_id; sch.loss(gold_heads[last] != heads[last] ? 2 : (gold_tags[last] != t_id) ? 1.f : 0.f); assert(!stack.empty()); - stack.pop(); + stack.pop_back(); return idx; } else if (a_id == REDUCE_LEFT) { - size_t last = stack.last(); + size_t last = stack.back(); uint32_t hd = idx; heads[last] = hd; children[3][hd] = children[2][hd]; @@ -185,7 +185,7 @@ size_t transition_hybrid(Search::search &sch, uint64_t a_id, uint32_t idx, uint3 tags[last] = t_id; sch.loss(gold_heads[last] != heads[last] ? 2 : (gold_tags[last] != t_id) ? 1.f : 0.f); assert(!stack.empty()); - stack.pop(); + stack.pop_back(); return idx; } THROW("transition_hybrid failed"); @@ -205,7 +205,7 @@ size_t transition_eager(Search::search &sch, uint64_t a_id, uint32_t idx, uint32 } else if (a_id == REDUCE_RIGHT) { - uint32_t hd = stack.last(); + uint32_t hd = stack.back(); stack.push_back(idx); uint32_t last = idx; heads[last] = hd; @@ -218,7 +218,7 @@ size_t transition_eager(Search::search &sch, uint64_t a_id, uint32_t idx, uint32 } else if (a_id == REDUCE_LEFT) { - size_t last = stack.last(); + size_t last = stack.back(); uint32_t hd = (idx > n) ? 0 : idx; heads[last] = hd; children[3][hd] = children[2][hd]; @@ -227,13 +227,13 @@ size_t transition_eager(Search::search &sch, uint64_t a_id, uint32_t idx, uint32 tags[last] = t_id; sch.loss(gold_heads[last] != heads[last] ? 2 : (gold_tags[last] != t_id) ? 1.f : 0.f); assert(!stack.empty()); - stack.pop(); + stack.pop_back(); return idx; } else if (a_id == REDUCE) { assert(!stack.empty()); - stack.pop(); + stack.pop_back(); return idx; } THROW("transition_eager failed"); @@ -253,7 +253,7 @@ void extract_features(Search::search &sch, uint32_t idx, multi_ex &ec) size_t n = ec.size(); bool empty = stack.empty(); - size_t last = empty ? 0 : stack.last(); + size_t last = empty ? 0 : stack.back(); for (size_t i = 0; i < 13; i++) ec_buf[i] = nullptr; @@ -345,7 +345,7 @@ void get_valid_actions(Search::search &sch, v_array &valid_action, uin if (stack_depth == 0) temp[REDUCE] = 0; - else if (idx <= n + 1 && heads[stack.last()] == my_null) + else if (idx <= n + 1 && heads[stack.back()] == my_null) temp[REDUCE] = 0; if (stack_depth == 0) @@ -355,7 +355,7 @@ void get_valid_actions(Search::search &sch, v_array &valid_action, uin } else { - if (heads[stack.last()] != my_null) + if (heads[stack.back()] != my_null) temp[REDUCE_LEFT] = 0; if (idx <= n && heads[idx] != my_null) temp[REDUCE_RIGHT] = 0; @@ -382,7 +382,7 @@ void get_eager_action_cost(Search::search &sch, uint32_t idx, uint64_t n) v_array &action_loss = data->action_loss, &stack = data->stack, &gold_heads = data->gold_heads, heads = data->heads; size_t size = stack.size(); - size_t last = (size == 0) ? 0 : stack.last(); + size_t last = (size == 0) ? 0 : stack.back(); for (size_t i = 1; i <= 4; i++) action_loss[i] = 0; if (!stack.empty()) for (size_t i = 0; i < size; i++) @@ -422,7 +422,7 @@ void get_hybrid_action_cost(Search::search &sch, size_t idx, uint64_t n) task_data *data = sch.get_task_data(); v_array &action_loss = data->action_loss, &stack = data->stack, &gold_heads = data->gold_heads; size_t size = stack.size(); - size_t last = (size == 0) ? 0 : stack.last(); + size_t last = (size == 0) ? 0 : stack.back(); for (size_t i = 1; i <= 3; i++) action_loss[i] = 0; if (!stack.empty()) @@ -491,7 +491,7 @@ void get_gold_actions(Search::search &sch, uint32_t idx, uint64_t /* n */, v_arr &valid_actions = data->valid_actions; gold_actions.clear(); size_t size = stack.size(); - size_t last = (size == 0) ? 0 : stack.last(); + size_t last = (size == 0) ? 0 : stack.back(); uint32_t &sys = data->transition_system; if (sys == arc_hybrid && is_valid(SHIFT, valid_actions) && (stack.empty() || gold_heads[idx] == last)) @@ -627,16 +627,16 @@ void run(Search::search &sch, multi_ex &ec) extract_features(sch, idx, ec); computedFeatures = true; } - get_valid_actions(sch, valid_actions, idx, n, (uint64_t)stack.size(), stack.empty() ? 0 : stack.last()); + get_valid_actions(sch, valid_actions, idx, n, (uint64_t)stack.size(), stack.empty() ? 0 : stack.back()); if (sys == arc_hybrid) get_hybrid_action_cost(sch, idx, n); else if (sys == arc_eager) get_eager_action_cost(sch, idx, n); // get gold tag labels - left_label = stack.empty() ? my_null : gold_tags[stack.last()]; + left_label = stack.empty() ? my_null : gold_tags[stack.back()]; if (sys == arc_hybrid) - right_label = stack.empty() ? my_null : gold_tags[stack.last()]; + right_label = stack.empty() ? my_null : gold_tags[stack.back()]; else if (sys == arc_eager) right_label = idx <= n ? gold_tags[idx] : (uint32_t)data->root_label; else @@ -751,9 +751,9 @@ void run(Search::search &sch, multi_ex &ec) } if (sys == arc_hybrid) { - heads[stack.last()] = 0; - tags[stack.last()] = (uint32_t)data->root_label; - sch.loss((gold_heads[stack.last()] != heads[stack.last()])); + heads[stack.back()] = 0; + tags[stack.back()] = (uint32_t)data->root_label; + sch.loss((gold_heads[stack.back()] != heads[stack.back()])); } if (sch.output().good()) for (size_t i = 1; i <= n; i++) sch.output() << (heads[i]) << ":" << tags[i] << std::endl; diff --git a/vowpalwabbit/search_entityrelationtask.cc b/vowpalwabbit/search_entityrelationtask.cc index 0ce16573a36..8e17f3f79ca 100644 --- a/vowpalwabbit/search_entityrelationtask.cc +++ b/vowpalwabbit/search_entityrelationtask.cc @@ -155,7 +155,7 @@ size_t predict_entity( .set_allowed(my_task_data->y_allowed_entity) .set_learner_id(1) .predict(); - my_task_data->y_allowed_entity.pop(); + my_task_data->y_allowed_entity.pop_back(); } else { @@ -240,7 +240,7 @@ size_t predict_relation(Search::search& sch, example* ex, v_array& predi .add_condition(id1, 'a') .add_condition(id2, 'b') .predict(); - constrained_relation_labels.pop(); + constrained_relation_labels.pop_back(); } else { diff --git a/vowpalwabbit/search_graph.cc b/vowpalwabbit/search_graph.cc index dc7d7a9f546..1e557316cc2 100644 --- a/vowpalwabbit/search_graph.cc +++ b/vowpalwabbit/search_graph.cc @@ -354,7 +354,7 @@ void add_edge_features(Search::search& sch, task_data& D, size_t n, multi_ex& ec void del_edge_features(task_data& /*D*/, uint32_t n, multi_ex& ec) { - ec[n]->indices.pop(); + ec[n]->indices.pop_back(); features& fs = ec[n]->feature_space[neighbor_namespace]; ec[n]->total_sum_feat_sq -= fs.sum_feat_sq; ec[n]->num_features -= fs.size(); diff --git a/vowpalwabbit/slim/src/vw_slim_predict.cc b/vowpalwabbit/slim/src/vw_slim_predict.cc index 66c79274e3e..4b3e154f2f2 100644 --- a/vowpalwabbit/slim/src/vw_slim_predict.cc +++ b/vowpalwabbit/slim/src/vw_slim_predict.cc @@ -26,7 +26,7 @@ namespace_copy_guard::namespace_copy_guard(example_predict& ex, unsigned char ns namespace_copy_guard::~namespace_copy_guard() { - _ex.indices.pop(); + _ex.indices.pop_back(); if (_remove_ns) _ex.feature_space[_ns].clear(); } @@ -58,4 +58,4 @@ stride_shift_guard::~stride_shift_guard() for (auto& f : _ex.feature_space[ns]) f.index() >>= _shift; } -}; // namespace vw_slim \ No newline at end of file +}; // namespace vw_slim diff --git a/vowpalwabbit/v_array.h b/vowpalwabbit/v_array.h index 48b4ec9a72b..4695bd11350 100644 --- a/vowpalwabbit/v_array.h +++ b/vowpalwabbit/v_array.h @@ -21,6 +21,7 @@ #include "vw_exception.h" #endif +#include "future_compat.h" #include "memory.h" const size_t erase_point = ~((1u << 10u) - 1u); @@ -52,21 +53,38 @@ struct v_array // ~v_array() { // delete_v(); // } - T last() const { return *(_end - 1); } - T pop() { return *(--_end); } - bool empty() const { return _begin == _end; } - void decr() { _end--; } + inline T& back() { return *(_end - 1); } + inline const T& back() const { return *(_end - 1); } + inline void pop_back() { (--_end)->~T(); } + + VW_DEPRECATED("v_array::last() is deprecated. Use back()") + T last() const { return back(); } + + VW_DEPRECATED("v_array::pop() is deprecated. Use pop_back()") + T pop() + { + T ret = back(); + pop_back(); + return ret; + } + + inline bool empty() const { return _begin == _end; } + + VW_DEPRECATED("v_array::decr() is deprecated. Use pop_back()") + inline void decr() { _end--; } + VW_DEPRECATED("v_array::incr() is deprecated.") void incr() { if (_end == end_array) - resize(2 * (end_array - _begin) + 3); + resize(2 * capacity() + 3); _end++; } T& operator[](size_t i) const { return _begin[i]; } inline size_t size() const { return _end - _begin; } + inline size_t capacity() const { return end_array - _begin; } void resize(size_t length) { - if ((size_t)(end_array - _begin) != length) + if (capacity() != length) { size_t old_len = _end - _begin; T* temp = (T*)realloc(_begin, sizeof(T) * length); @@ -83,6 +101,27 @@ struct v_array } } + // insert() and remove() don't follow the standard spec, which calls for iterators + // instead of indices. But these fn signatures follow our usage better. + // These functions do not check bounds, undefined behavior if they are called + // on out-of-bounds indices + // insert before the indexed element + inline void insert(size_t idx, const T& elem) + { + if (_end == end_array) + resize(2 * capacity() + 3); + _end++; + memmove(&_begin[idx + 1], &_begin[idx], (size() - (idx + 1)) * sizeof(T)); + _begin[idx] = elem; + } + // erase indexed element + inline void erase(size_t idx) + { + _begin[idx].~T(); + memmove(&_begin[idx], &_begin[idx + 1], (size() - (idx + 1)) * sizeof(T)); + --_end; + } + void clear() { if (++erase_count & erase_point) @@ -105,7 +144,7 @@ struct v_array void push_back(const T& new_ele) { if (_end == end_array) - resize(2 * (end_array - _begin) + 3); + resize(2 * capacity() + 3); new (_end++) T(new_ele); } @@ -115,7 +154,7 @@ struct v_array void emplace_back(Args&&... args) { if (_end == end_array) - resize(2 * (end_array - _begin) + 3); + resize(2 * capacity() + 3); new (_end++) T(std::forward(args)...); } @@ -153,7 +192,7 @@ struct v_array if (!contain_sorted(new_ele, index)) { if (_end == end_array) - resize(2 * (end_array - _begin) + 3); + resize(2 * capacity() + 3); to_move = size - index; @@ -214,7 +253,7 @@ template void push_many(v_array& v, const T* _begin, size_t num) { if (v._end + num >= v.end_array) - v.resize(std::max(2 * (size_t)(v.end_array - v._begin) + 3, v._end - v._begin + num)); + v.resize(std::max(2 * v.capacity() + 3, v.size() + num)); #ifdef _WIN32 memcpy_s(v._end, v.size() - (num * sizeof(T)), _begin, num * sizeof(T)); #else diff --git a/vowpalwabbit/vwdll.cpp b/vowpalwabbit/vwdll.cpp index 7bb806c8346..71f09c8f48c 100644 --- a/vowpalwabbit/vwdll.cpp +++ b/vowpalwabbit/vwdll.cpp @@ -368,7 +368,7 @@ class memory_io_buf : public io_buf virtual bool close_file() { if (files.size() > 0) { - files.pop(); + files.pop_back(); return true; } return false; From 2fbc73fa5719c0b1d9c3a557e58849a4b0abaa2f Mon Sep 17 00:00:00 2001 From: peterychang Date: Thu, 2 Jan 2020 17:06:27 -0500 Subject: [PATCH 2/3] add r-value versions of functions --- vowpalwabbit/v_array.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/vowpalwabbit/v_array.h b/vowpalwabbit/v_array.h index 4695bd11350..2b157dea32b 100644 --- a/vowpalwabbit/v_array.h +++ b/vowpalwabbit/v_array.h @@ -110,9 +110,17 @@ struct v_array { if (_end == end_array) resize(2 * capacity() + 3); - _end++; + ++_end; + memmove(&_begin[idx + 1], &_begin[idx], (size() - (idx + 1)) * sizeof(T)); + new (&_begin[idx]) T(elem); + } + inline void insert(size_t idx, T&& elem) + { + if (_end == end_array) + resize(2 * capacity() + 3); + ++_end; memmove(&_begin[idx + 1], &_begin[idx], (size() - (idx + 1)) * sizeof(T)); - _begin[idx] = elem; + new (&_begin[idx]) T(std::move(elem)); } // erase indexed element inline void erase(size_t idx) @@ -147,6 +155,12 @@ struct v_array resize(2 * capacity() + 3); new (_end++) T(new_ele); } + void push_back(T&& new_ele) + { + if (_end == end_array) + resize(2 * capacity() + 3); + new (_end++) T(std::move(new_ele)); + } void push_back_unchecked(const T& new_ele) { new (_end++) T(new_ele); } From 792d83233d0e1bcfde9030e90ab51003c37951b5 Mon Sep 17 00:00:00 2001 From: peterychang Date: Fri, 3 Jan 2020 11:56:47 -0500 Subject: [PATCH 3/3] add asserts and comments --- vowpalwabbit/v_array.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vowpalwabbit/v_array.h b/vowpalwabbit/v_array.h index 2b157dea32b..b2fe504f870 100644 --- a/vowpalwabbit/v_array.h +++ b/vowpalwabbit/v_array.h @@ -104,10 +104,14 @@ struct v_array // insert() and remove() don't follow the standard spec, which calls for iterators // instead of indices. But these fn signatures follow our usage better. // These functions do not check bounds, undefined behavior if they are called - // on out-of-bounds indices + // on out-of-bounds indices. + // NOTE: this function is only safe for trivially copyable objects + // any object that contains internal pointers or refernces will break + // when using these functions // insert before the indexed element inline void insert(size_t idx, const T& elem) { + assert(idx <= size()); if (_end == end_array) resize(2 * capacity() + 3); ++_end; @@ -116,6 +120,7 @@ struct v_array } inline void insert(size_t idx, T&& elem) { + assert(idx <= size()); if (_end == end_array) resize(2 * capacity() + 3); ++_end; @@ -125,6 +130,7 @@ struct v_array // erase indexed element inline void erase(size_t idx) { + assert(idx < size()); _begin[idx].~T(); memmove(&_begin[idx], &_begin[idx + 1], (size() - (idx + 1)) * sizeof(T)); --_end;