Avoid creating CardGenContexts for every note

This requires CardGenContext to be generic, so it works both with an
owned and borrowed notetype.
This commit is contained in:
RumovZ 2022-05-11 10:59:49 +02:00
parent fe862523e6
commit b740be6554
5 changed files with 47 additions and 31 deletions

View file

@ -262,7 +262,11 @@ impl Collection {
// write note, updating tags and generating missing cards // write note, updating tags and generating missing cards
let ctx = genctx.get_or_insert_with(|| { let ctx = genctx.get_or_insert_with(|| {
CardGenContext::new(&nt, self.get_last_deck_added_to_for_notetype(nt.id), usn) CardGenContext::new(
nt.as_ref(),
self.get_last_deck_added_to_for_notetype(nt.id),
usn,
)
}); });
self.update_note_inner_generating_cards( self.update_note_inner_generating_cards(
ctx, &mut note, &original, false, norm, true, ctx, &mut note, &original, false, norm, true,

View file

@ -32,6 +32,7 @@ struct Context<'a> {
deck_ids: HashMap<String, Option<DeckId>>, deck_ids: HashMap<String, Option<DeckId>>,
usn: Usn, usn: Usn,
normalize_notes: bool, normalize_notes: bool,
card_gen_ctxs: HashMap<(NotetypeId, DeckId), CardGenContext<Arc<Notetype>>>,
//progress: IncrementableProgress<ImportProgress>, //progress: IncrementableProgress<ImportProgress>,
} }
@ -52,6 +53,7 @@ impl<'a> Context<'a> {
normalize_notes, normalize_notes,
notetypes, notetypes,
deck_ids, deck_ids,
card_gen_ctxs: HashMap::new(),
}) })
} }
@ -89,7 +91,7 @@ impl<'a> Context<'a> {
for foreign in notes { for foreign in notes {
if let Some(notetype) = self.notetype_for_note(&foreign)? { if let Some(notetype) = self.notetype_for_note(&foreign)? {
if let Some(deck_id) = self.deck_id_for_note(&foreign)? { if let Some(deck_id) = self.deck_id_for_note(&foreign)? {
let log_note = self.import_foreign_note(foreign, &notetype, deck_id)?; let log_note = self.import_foreign_note(foreign, notetype, deck_id)?;
log.new.push(log_note); log.new.push(log_note);
} }
} }
@ -100,12 +102,12 @@ impl<'a> Context<'a> {
fn import_foreign_note( fn import_foreign_note(
&mut self, &mut self,
foreign: ForeignNote, foreign: ForeignNote,
notetype: &Notetype, notetype: Arc<Notetype>,
deck_id: DeckId, deck_id: DeckId,
) -> Result<LogNote> { ) -> Result<LogNote> {
let today = self.col.timing_today()?.days_elapsed; let today = self.col.timing_today()?.days_elapsed;
let (mut note, mut cards) = foreign.into_native(notetype, deck_id, today); let (mut note, mut cards) = foreign.into_native(&notetype, deck_id, today);
self.import_note(&mut note, notetype)?; self.import_note(&mut note, &notetype)?;
self.import_cards(&mut cards, note.id)?; self.import_cards(&mut cards, note.id)?;
self.generate_missing_cards(notetype, deck_id, &note)?; self.generate_missing_cards(notetype, deck_id, &note)?;
Ok(note.into_log_note()) Ok(note.into_log_note())
@ -128,13 +130,16 @@ impl<'a> Context<'a> {
fn generate_missing_cards( fn generate_missing_cards(
&mut self, &mut self,
notetype: &Notetype, notetype: Arc<Notetype>,
deck_id: DeckId, deck_id: DeckId,
note: &Note, note: &Note,
) -> Result<()> { ) -> Result<()> {
let card_gen_context = CardGenContext::new(notetype, Some(deck_id), self.usn); let card_gen_context = self
.card_gen_ctxs
.entry((notetype.id, deck_id))
.or_insert_with(|| CardGenContext::new(notetype, Some(deck_id), self.usn));
self.col self.col
.generate_cards_for_existing_note(&card_gen_context, note) .generate_cards_for_existing_note(card_gen_context, note)
} }
} }

View file

@ -80,7 +80,7 @@ impl Collection {
.get_notetype(note.notetype_id)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?; .ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let last_deck = col.get_last_deck_added_to_for_notetype(note.notetype_id); let last_deck = col.get_last_deck_added_to_for_notetype(note.notetype_id);
let ctx = CardGenContext::new(&nt, last_deck, col.usn()?); let ctx = CardGenContext::new(nt.as_ref(), last_deck, col.usn()?);
let norm = col.get_config_bool(BoolKey::NormalizeNoteText); let norm = col.get_config_bool(BoolKey::NormalizeNoteText);
col.add_note_inner(&ctx, note, did, norm) col.add_note_inner(&ctx, note, did, norm)
}) })
@ -334,7 +334,7 @@ impl Collection {
pub(crate) fn add_note_inner( pub(crate) fn add_note_inner(
&mut self, &mut self,
ctx: &CardGenContext, ctx: &CardGenContext<&Notetype>,
note: &mut Note, note: &mut Note,
did: DeckId, did: DeckId,
normalize_text: bool, normalize_text: bool,
@ -397,7 +397,7 @@ impl Collection {
.get_notetype(note.notetype_id)? .get_notetype(note.notetype_id)?
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?; .ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let last_deck = self.get_last_deck_added_to_for_notetype(note.notetype_id); let last_deck = self.get_last_deck_added_to_for_notetype(note.notetype_id);
let ctx = CardGenContext::new(&nt, last_deck, self.usn()?); let ctx = CardGenContext::new(nt.as_ref(), last_deck, self.usn()?);
let norm = self.get_config_bool(BoolKey::NormalizeNoteText); let norm = self.get_config_bool(BoolKey::NormalizeNoteText);
self.update_note_inner_generating_cards(&ctx, note, &existing_note, true, norm, true)?; self.update_note_inner_generating_cards(&ctx, note, &existing_note, true, norm, true)?;
Ok(()) Ok(())
@ -405,7 +405,7 @@ impl Collection {
pub(crate) fn update_note_inner_generating_cards( pub(crate) fn update_note_inner_generating_cards(
&mut self, &mut self,
ctx: &CardGenContext, ctx: &CardGenContext<&Notetype>,
note: &mut Note, note: &mut Note,
original: &Note, original: &Note,
mark_note_modified: bool, mark_note_modified: bool,
@ -508,7 +508,7 @@ impl Collection {
if out.generate_cards { if out.generate_cards {
let ctx = genctx.get_or_insert_with(|| { let ctx = genctx.get_or_insert_with(|| {
CardGenContext::new( CardGenContext::new(
&nt, nt.as_ref(),
self.get_last_deck_added_to_for_notetype(nt.id), self.get_last_deck_added_to_for_notetype(nt.id),
usn, usn,
) )

View file

@ -1,7 +1,10 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use std::collections::{HashMap, HashSet}; use std::{
collections::{HashMap, HashSet},
ops::Deref,
};
use itertools::Itertools; use itertools::Itertools;
use rand::{rngs::StdRng, Rng, SeedableRng}; use rand::{rngs::StdRng, Rng, SeedableRng};
@ -38,9 +41,9 @@ pub(crate) struct SingleCardGenContext {
/// Info required to determine which cards should be generated when note added/updated, /// Info required to determine which cards should be generated when note added/updated,
/// and where they should be placed. /// and where they should be placed.
pub(crate) struct CardGenContext<'a> { pub(crate) struct CardGenContext<N: Deref<Target = Notetype>> {
pub usn: Usn, pub usn: Usn,
pub notetype: &'a Notetype, pub notetype: N,
/// The last deck that was added to with this note type /// The last deck that was added to with this note type
pub last_deck: Option<DeckId>, pub last_deck: Option<DeckId>,
cards: Vec<SingleCardGenContext>, cards: Vec<SingleCardGenContext>,
@ -53,20 +56,21 @@ pub(crate) struct CardGenCache {
deck_configs: HashMap<DeckId, DeckConfig>, deck_configs: HashMap<DeckId, DeckConfig>,
} }
impl CardGenContext<'_> { impl<N: Deref<Target = Notetype>> CardGenContext<N> {
pub(crate) fn new(nt: &Notetype, last_deck: Option<DeckId>, usn: Usn) -> CardGenContext<'_> { pub(crate) fn new(nt: N, last_deck: Option<DeckId>, usn: Usn) -> CardGenContext<N> {
CardGenContext { let cards = nt
usn,
last_deck,
notetype: nt,
cards: nt
.templates .templates
.iter() .iter()
.map(|tmpl| SingleCardGenContext { .map(|tmpl| SingleCardGenContext {
template: tmpl.parsed_question(), template: tmpl.parsed_question(),
target_deck_id: tmpl.target_deck_id(), target_deck_id: tmpl.target_deck_id(),
}) })
.collect(), .collect();
CardGenContext {
usn,
last_deck,
notetype: nt,
cards,
} }
} }
@ -209,7 +213,7 @@ pub(crate) fn extract_data_from_existing_cards(
impl Collection { impl Collection {
pub(crate) fn generate_cards_for_new_note( pub(crate) fn generate_cards_for_new_note(
&mut self, &mut self,
ctx: &CardGenContext, ctx: &CardGenContext<impl Deref<Target = Notetype>>,
note: &Note, note: &Note,
target_deck_id: DeckId, target_deck_id: DeckId,
) -> Result<()> { ) -> Result<()> {
@ -224,7 +228,7 @@ impl Collection {
pub(crate) fn generate_cards_for_existing_note( pub(crate) fn generate_cards_for_existing_note(
&mut self, &mut self,
ctx: &CardGenContext, ctx: &CardGenContext<impl Deref<Target = Notetype>>,
note: &Note, note: &Note,
) -> Result<()> { ) -> Result<()> {
let existing = self.storage.existing_cards_for_note(note.id)?; let existing = self.storage.existing_cards_for_note(note.id)?;
@ -233,7 +237,7 @@ impl Collection {
fn generate_cards_for_note( fn generate_cards_for_note(
&mut self, &mut self,
ctx: &CardGenContext, ctx: &CardGenContext<impl Deref<Target = Notetype>>,
note: &Note, note: &Note,
existing: &[AlreadyGeneratedCardInfo], existing: &[AlreadyGeneratedCardInfo],
target_deck_id: Option<DeckId>, target_deck_id: Option<DeckId>,
@ -246,7 +250,10 @@ impl Collection {
self.add_generated_cards(note.id, &cards, target_deck_id, cache) self.add_generated_cards(note.id, &cards, target_deck_id, cache)
} }
pub(crate) fn generate_cards_for_notetype(&mut self, ctx: &CardGenContext) -> Result<()> { pub(crate) fn generate_cards_for_notetype(
&mut self,
ctx: &CardGenContext<impl Deref<Target = Notetype>>,
) -> Result<()> {
let existing_cards = self.storage.existing_cards_for_notetype(ctx.notetype.id)?; let existing_cards = self.storage.existing_cards_for_notetype(ctx.notetype.id)?;
let by_note = group_generated_cards_by_note(existing_cards); let by_note = group_generated_cards_by_note(existing_cards);
let mut cache = CardGenCache::default(); let mut cache = CardGenCache::default();

View file

@ -255,7 +255,7 @@ impl Collection {
.get_notetype(new_notetype_id)? .get_notetype(new_notetype_id)?
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let last_deck = self.get_last_deck_added_to_for_notetype(notetype.id); let last_deck = self.get_last_deck_added_to_for_notetype(notetype.id);
let ctx = CardGenContext::new(&notetype, last_deck, usn); let ctx = CardGenContext::new(notetype.as_ref(), last_deck, usn);
for nid in note_ids { for nid in note_ids {
let mut note = self.storage.get_note(*nid)?.ok_or(AnkiError::NotFound)?; let mut note = self.storage.get_note(*nid)?.ok_or(AnkiError::NotFound)?;