Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 319d244

Browse files
authored
Improve complexity of CompactAssignments::unique_targets (#8314)
* Improve complexity of CompactAssignments::unique_targets Original implementation was O(n**2). Current impl is O(n log n). Avoided the original proposed mitigation because it does not retain the de-duplicating property present in the original implementation. This implementation does a little more work, but retains that property. * Explicitly choose sp_std Vec and BTreeSet Ensures that the macro still works if someone uses it in a context in which sp_std is not imported or is renamed. * explicitly use sp_std vectors throughout compact macro
1 parent 3f434df commit 319d244

File tree

4 files changed

+25
-24
lines changed

4 files changed

+25
-24
lines changed

primitives/npos-elections/compact/src/assignment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub(crate) fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 {
125125
let target = target_at(*t_idx).or_invalid_index()?;
126126
Ok((target, *p))
127127
})
128-
.collect::<Result<Vec<(A, #per_thing)>, _npos::Error>>()?;
128+
.collect::<Result<_npos::sp_std::prelude::Vec<(A, #per_thing)>, _npos::Error>>()?;
129129

130130
if sum >= #per_thing::one() {
131131
return Err(_npos::Error::CompactStakeOverflow);

primitives/npos-elections/compact/src/codec.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ fn decode_impl(
4949
quote! {
5050
let #name =
5151
<
52-
Vec<(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)>
52+
_npos::sp_std::prelude::Vec<(_npos::codec::Compact<#voter_type>, _npos::codec::Compact<#target_type>)>
5353
as
5454
_npos::codec::Decode
5555
>::decode(value)?;
5656
let #name = #name
5757
.into_iter()
5858
.map(|(v, t)| (v.0, t.0))
59-
.collect::<Vec<_>>();
59+
.collect::<_npos::sp_std::prelude::Vec<_>>();
6060
}
6161
};
6262

@@ -65,7 +65,7 @@ fn decode_impl(
6565
quote! {
6666
let #name =
6767
<
68-
Vec<(
68+
_npos::sp_std::prelude::Vec<(
6969
_npos::codec::Compact<#voter_type>,
7070
(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>),
7171
_npos::codec::Compact<#target_type>,
@@ -76,7 +76,7 @@ fn decode_impl(
7676
let #name = #name
7777
.into_iter()
7878
.map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0))
79-
.collect::<Vec<_>>();
79+
.collect::<_npos::sp_std::prelude::Vec<_>>();
8080
}
8181
};
8282

@@ -90,7 +90,7 @@ fn decode_impl(
9090
quote! {
9191
let #name =
9292
<
93-
Vec<(
93+
_npos::sp_std::prelude::Vec<(
9494
_npos::codec::Compact<#voter_type>,
9595
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
9696
_npos::codec::Compact<#target_type>,
@@ -104,7 +104,7 @@ fn decode_impl(
104104
[ #inner_impl ],
105105
t_last.0,
106106
))
107-
.collect::<Vec<_>>();
107+
.collect::<_npos::sp_std::prelude::Vec<_>>();
108108
}
109109
}).collect::<TokenStream2>();
110110

@@ -142,7 +142,7 @@ fn encode_impl(ident: syn::Ident, count: usize) -> TokenStream2 {
142142
_npos::codec::Compact(v.clone()),
143143
_npos::codec::Compact(t.clone()),
144144
))
145-
.collect::<Vec<_>>();
145+
.collect::<_npos::sp_std::prelude::Vec<_>>();
146146
#name.encode_to(&mut r);
147147
}
148148
};
@@ -160,7 +160,7 @@ fn encode_impl(ident: syn::Ident, count: usize) -> TokenStream2 {
160160
),
161161
_npos::codec::Compact(t2.clone()),
162162
))
163-
.collect::<Vec<_>>();
163+
.collect::<_npos::sp_std::prelude::Vec<_>>();
164164
#name.encode_to(&mut r);
165165
}
166166
};
@@ -184,14 +184,14 @@ fn encode_impl(ident: syn::Ident, count: usize) -> TokenStream2 {
184184
[ #inners_compact_array ],
185185
_npos::codec::Compact(t_last.clone()),
186186
))
187-
.collect::<Vec<_>>();
187+
.collect::<_npos::sp_std::prelude::Vec<_>>();
188188
#name.encode_to(&mut r);
189189
}
190190
}).collect::<TokenStream2>();
191191

192192
quote!(
193193
impl _npos::codec::Encode for #ident {
194-
fn encode(&self) -> Vec<u8> {
194+
fn encode(&self) -> _npos::sp_std::prelude::Vec<u8> {
195195
let mut r = vec![];
196196
#encode_impl_single
197197
#encode_impl_double

primitives/npos-elections/compact/src/lib.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,14 @@ fn struct_def(
119119
let name = field_name_for(1);
120120
// NOTE: we use the visibility of the struct for the fields as well.. could be made better.
121121
quote!(
122-
#vis #name: Vec<(#voter_type, #target_type)>,
122+
#vis #name: _npos::sp_std::prelude::Vec<(#voter_type, #target_type)>,
123123
)
124124
};
125125

126126
let doubles = {
127127
let name = field_name_for(2);
128128
quote!(
129-
#vis #name: Vec<(#voter_type, (#target_type, #weight_type), #target_type)>,
129+
#vis #name: _npos::sp_std::prelude::Vec<(#voter_type, (#target_type, #weight_type), #target_type)>,
130130
)
131131
};
132132

@@ -135,7 +135,7 @@ fn struct_def(
135135
let field_name = field_name_for(c);
136136
let array_len = c - 1;
137137
quote!(
138-
#vis #field_name: Vec<(
138+
#vis #field_name: _npos::sp_std::prelude::Vec<(
139139
#voter_type,
140140
[(#target_type, #weight_type); #array_len],
141141
#target_type
@@ -194,20 +194,19 @@ fn struct_def(
194194
all_edges
195195
}
196196

197-
fn unique_targets(&self) -> Vec<Self::Target> {
197+
fn unique_targets(&self) -> _npos::sp_std::prelude::Vec<Self::Target> {
198198
// NOTE: this implementation returns the targets sorted, but we don't use it yet per
199199
// se, nor is the API enforcing it.
200-
let mut all_targets: Vec<Self::Target> = Vec::with_capacity(self.average_edge_count());
200+
use _npos::sp_std::collections::btree_set::BTreeSet;
201+
202+
let mut all_targets: BTreeSet<Self::Target> = BTreeSet::new();
201203
let mut maybe_insert_target = |t: Self::Target| {
202-
match all_targets.binary_search(&t) {
203-
Ok(_) => (),
204-
Err(pos) => all_targets.insert(pos, t)
205-
}
204+
all_targets.insert(t);
206205
};
207206

208207
#unique_targets_impl
209208

210-
all_targets
209+
all_targets.into_iter().collect()
211210
}
212211

213212
fn remove_voter(&mut self, to_remove: Self::Voter) -> bool {
@@ -216,7 +215,7 @@ fn struct_def(
216215
}
217216

218217
fn from_assignment<FV, FT, A>(
219-
assignments: Vec<_npos::Assignment<A, #weight_type>>,
218+
assignments: _npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>>,
220219
index_of_voter: FV,
221220
index_of_target: FT,
222221
) -> Result<Self, _npos::Error>
@@ -243,8 +242,8 @@ fn struct_def(
243242
self,
244243
voter_at: impl Fn(Self::Voter) -> Option<A>,
245244
target_at: impl Fn(Self::Target) -> Option<A>,
246-
) -> Result<Vec<_npos::Assignment<A, #weight_type>>, _npos::Error> {
247-
let mut assignments: Vec<_npos::Assignment<A, #weight_type>> = Default::default();
245+
) -> Result<_npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>>, _npos::Error> {
246+
let mut assignments: _npos::sp_std::prelude::Vec<_npos::Assignment<A, #weight_type>> = Default::default();
248247
#into_impl
249248
Ok(assignments)
250249
}

primitives/npos-elections/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub use pjr::*;
119119
pub use codec;
120120
#[doc(hidden)]
121121
pub use sp_arithmetic;
122+
#[doc(hidden)]
123+
pub use sp_std;
122124

123125
/// Simple Extension trait to easily convert `None` from index closures to `Err`.
124126
///

0 commit comments

Comments
 (0)