1.アイテムの取得(その1の続き) |
Public Function GetAt(ByVal Index As Long) As KnotItem ' 指定したインデックスのアイテムを返します。 Dim lb As Long, b As Long With mManager lb = .LadderBase b = Abs(Index - mIndex) - lb If (Index > .LastItem.Index) Or (Index < 1) Then Set GetAt = Nothing Exit Function ElseIf b > 0 Then lb = lb * (Index \ lb) b = Abs(Index - lb) If b >= .LadderBase / 2 Then lb = lb + .LadderBase * IIf(Index - lb < 0, -1, 1) Select Case lb Case Is > .LastItem.Index Set GetAt = .LastItem.GetAt(Index) Case Is < 1 Set GetAt = .FirstItem.GetAt(Index) Case Else Set GetAt = .Ladder("#" & CStr(lb)).GetAt(Index) End Select Exit Function End If End With Select Case Index Case mIndex Set GetAt = Me Case Is > mIndex If mNext Is Nothing Then Set GetAt = Nothing Else Set GetAt = mNext.GetAt(Index) End If Case Else If mPrev Is Nothing Then Set GetAt = Nothing Else Set GetAt = mPrev.GetAt(Index) End If End Select End Function このメソッドはマネージャのプロパティなどと大いに関係があるため、こちらに載せました。まず、前半(〜End With)と後半(Select Case〜)に分けて説明していきたいと思います。 前半では、簡単に言えば位置判定を行っています。 ラダー(Ladder : はしご)オブジェクトというコレクションをマネージャ内部に忍ばせていますが、これは検索スピードをアップさせるためのものです。 またあまり多くのKnotItemオブジェクトをつなげた場合、このメソッドでは再帰処理を行っているのでスタック不足に陥る可能性があるのでそのための対処ということもあります。 そして後半部分では現在の位置において検索すべき方向にある隣のKnotItemオブジェクトのGetAtメソッドを実行して、行き着くところ(KnotItemに格納されているIndexと引数のIndexが一致する)まで繰り返します。 具体例で説明してみましょう。左の図のような状態を考えてみます。 青の線で示した、GetAt()が実行されたアイテムと、目的とするアイテム(赤の線)のインデックスとの幅を調べ、その幅がラダーの間隔より大きいかどうか調べます。大きい場合、次のラダーコレクションの要素(矢印の方向にある黒い線)に一気に飛びます(前半部分)。そして、そこから一つ一つ矢印の方向に調べていくのです(後半部分)。 Friend Sub SetNumbers(ByVal NewIndex As Long, Optional ByVal NewManager As KnotManager) Dim k As String If NewIndex < 1 Then Err.Raise 5 Exit Sub End If mIndex = NewIndex ' (前の項と)マネージャが違えば交換する If Not (NewManager Is Nothing) Then If Not (NewManager Is mManager) Then Set mManager = NewManager ElseIf Not (mPrev Is Nothing) Then If (Not (mManager Is mPrev.Manager)) And (Not (mPrev.Manager Is Nothing)) Then Set mManager = mPrev.Manager End If With mManager If NewIndex = 1 Then .FirstItem = Me .Ladder = New Collection ElseIf (NewIndex Mod .LadderBase) = 0 Then ' 30位が適当? k = "#" & CStr(NewIndex) On Error Resume Next .Ladder.Add Me, k If Err.Number <> 0 Then Set .Ladder(k) = Me Err.Clear On Error GoTo 0 End If End With If Not (mNext Is Nothing) Then ' 最後に達していなければ、次に回す If Not (NewManager Is Nothing) Then mNext.SetNumbers NewIndex + 1, NewManager Else mNext.SetNumbers NewIndex + 1 End If Else ' 最後なら、最終アイテムを設定して終了 mManager.LastItem = Me End If End Sub 見て気づくかもしれませんが、このGetAt()メソッドとSetNumbers()では、再帰処理がふんだんに使われています。再帰処理(recursive process)は、検索や並べ替え、連続処理に対して有効な場合が数多くあります。 この関数は、じっくり見ればコメントが少なくてもきっと分かるはずです。じっくり解読してみてください。 |
2.マネージャのメソッド |
CreateAndAttach, CreateNewItem, AttachListItemsがこのマネージャの主要なメソッドですが、これらメソッドがやっていることは全て同じです。
新しいKnotItemオブジェクトを作成して(AttachListItems()では作成しません)自らのFirstItemプロパティにこの新しく作った(AttachListItems()では指定された)アイテムを設定する。そして、SetNumbers()メソッドで番号を整理しているだけなのです。 簡単ですが、本当にこれだけのことなのです。 次回は、利用例を載せることができれば、と思っています。 |