/* Function: PickNewTopics * Returns the IDs for a batch of new topics and their shared ending symbol, or false if there aren't any. This allows you to process * new topics that could potentially serve as better definitions to existing links. */ public bool PickNewTopics(out IDObjects.NumberSet topicIDs, out EndingSymbol endingSymbol) { lock (accessLock) { if (newTopicIDsByEndingSymbol.Count == 0) { topicIDs = null; endingSymbol = default(EndingSymbol); return(false); } else { // Once links might be resolved we can't allow this optimization anymore. See the variable's documentation for // the explanation. ignoreNewTopics = false; var enumerator = newTopicIDsByEndingSymbol.GetEnumerator(); enumerator.MoveNext(); // It's not positioned on the first element by default. endingSymbol = enumerator.Current.Key; topicIDs = enumerator.Current.Value; newTopicIDsByEndingSymbol.Remove(endingSymbol); return(true); } } }
/* Function: PickEndingSymbolToResolve * If <newTopicIDsByEndingSymbol> isn't empty it will remove one from the list and return true. Otherwise * returns false. Handles locking automatically. */ protected bool PickEndingSymbolToResolve(out EndingSymbol endingSymbol, out NumberSet topicIDs) { Monitor.Enter(newTopicIDsByEndingSymbol); try { if (newTopicIDsByEndingSymbol.Count == 0) { endingSymbol = default(EndingSymbol); topicIDs = null; return(false); } else { var enumerator = newTopicIDsByEndingSymbol.GetEnumerator(); enumerator.MoveNext(); // It's not positioned on the first element by default. endingSymbol = enumerator.Current.Key; topicIDs = enumerator.Current.Value; newTopicIDsByEndingSymbol.Remove(endingSymbol); return(true); } } finally { Monitor.Exit(newTopicIDsByEndingSymbol); } }
/* Function: FinalizeNewTopics * Finalizes processing of a set of new topics and their shared ending symbol. */ protected void FinalizeNewTopics(IDObjects.NumberSet topicIDs, EndingSymbol endingSymbol) { lock (accessLock) { // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count changesBeingProcessed -= topicIDs.Count; } }
/* Function: PickNewTopics * Returns the IDs for a batch of new topics and their shared ending symbol, or false if there aren't any. This allows * you to process new topics that could potentially serve as better definitions to existing links. You must pass the values * to <FinalizeNewTopics()> after resolving them. */ protected bool PickNewTopics(out IDObjects.NumberSet topicIDs, out EndingSymbol endingSymbol) { lock (accessLock) { if (Manager.UnprocessedChanges.PickNewTopics(out topicIDs, out endingSymbol)) { // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count changesBeingProcessed += topicIDs.Count; return true; } else { return false; } } }
// Group: Functions // __________________________________________________________________________ public Link() { linkID = 0; type = LinkType.NaturalDocs; textOrSymbol = null; context = new ContextString(); contextID = 0; fileID = 0; classString = new ClassString(); classID = 0; languageID = 0; endingSymbol = new EndingSymbol(); targetTopicID = 0; targetClassID = 0; targetScore = 0; ignoredFields = IgnoreFields.None; }
/* Function: ResolveNewTopics * * Goes through the IDs of newly created <Topics> and sees if they serve as better targets for any existing * links. * * Parameters: * * topicIDs - The set of IDs to check. Every <Topic> represented here must have the same <EndingSymbol>. * endingSymbol - The <EndingSymbol> shared by all of the topic IDs. * accessor - The <Accessor> used for the database. * * Requirements: * * - Requires the accessor to have at least a read/possible write lock. If the link changes it will be upgraded to * read/write automatically. * */ protected void ResolveNewTopics(IDObjects.NumberSet topicIDs, EndingSymbol endingSymbol, Accessor accessor) { // We only need the body's length, not its contents. List <Topic> topics = accessor.GetTopicsByID(topicIDs, Delegates.NeverCancel, Accessor.GetTopicFlags.BodyLengthOnly | Accessor.GetTopicFlags.DontLookupClasses | Accessor.GetTopicFlags.DontLookupContexts); List <Link> links = accessor.GetLinksByEndingSymbol(endingSymbol, Delegates.NeverCancel, Accessor.GetLinkFlags.DontLookupClasses); // Go through each link and see if any of the topics serve as a better target. It's better for the links to be the outer loop // because we can generate alternate interpretations only once per link. foreach (Link link in links) { List <LinkInterpretation> alternateInterpretations = null; if (link.Type == LinkType.NaturalDocs) { string ignore; alternateInterpretations = EngineInstance.Comments.NaturalDocsParser.LinkInterpretations(link.Text, Comments.Parsers.NaturalDocs.LinkInterpretationFlags.FromOriginalText | Comments.Parsers.NaturalDocs.LinkInterpretationFlags.AllowNamedLinks | Comments.Parsers.NaturalDocs.LinkInterpretationFlags.AllowPluralsAndPossessives, out ignore); } int bestMatchTopicID = link.TargetTopicID; int bestMatchClassID = link.TargetClassID; long bestMatchScore = link.TargetScore; foreach (Topic topic in topics) { // No use rescoring the existing target. if (topic.TopicID != link.TargetTopicID) { long score = EngineInstance.Links.Score(link, topic, bestMatchScore, alternateInterpretations); if (score > bestMatchScore) { bestMatchTopicID = topic.TopicID; bestMatchClassID = topic.ClassID; bestMatchScore = score; } } } if (bestMatchTopicID != link.TargetTopicID || bestMatchClassID != link.TargetClassID || bestMatchScore != link.TargetScore) { int oldTargetTopicID = link.TargetTopicID; int oldTargetClassID = link.TargetClassID; link.TargetTopicID = bestMatchTopicID; link.TargetClassID = bestMatchClassID; link.TargetScore = bestMatchScore; accessor.UpdateLinkTarget(link, oldTargetTopicID, oldTargetClassID); } } }