OSDN Git Service

Allow NUL and \\.\NUL in paths specified as command line arguments (#2056)
[winmerge-jp/winmerge-jp.git] / Src / CompareStats.cpp
1 /** 
2  * @file  CompareStats.cpp
3  *
4  * @brief Implementation of CompareStats class.
5  */
6
7 #include "pch.h"
8 #include "CompareStats.h"
9 #include <cassert>
10 #include <cstring>
11 #include <atomic>
12 #include "DiffItem.h"
13
14 /** 
15  * @brief Constructor, initializes critical section.
16  */
17 CompareStats::CompareStats(int nDirs)
18 : m_nTotalItems(0)
19 , m_nComparedItems(0)
20 , m_state(STATE_IDLE)
21 , m_bCompareDone(false)
22 , m_nDirs(nDirs)
23 , m_counts()
24 , m_nIdleCompareThreadCount(0)
25 {
26 }
27
28 /** 
29  * @brief Destructor, deletes critical section.
30  */
31 CompareStats::~CompareStats() = default;
32
33 /** 
34  * @brief Add compared item.
35  * @param [in] code Resultcode to add.
36  */
37 void CompareStats::AddItem(int code)
38 {
39         if (code != -1)
40         {
41                 RESULT res = GetResultFromCode(code);
42                 int index = static_cast<int>(res);
43                 m_counts[index]++;
44         }
45         ++m_nComparedItems;
46         assert(m_nComparedItems <= m_nTotalItems);
47 }
48
49 /**
50 * @brief Return item taking most time among current items.
51 */
52 const DIFFITEM *CompareStats::GetCurDiffItem()
53 {
54         int nHitCountMax = 0;
55         const DIFFITEM *cdi = m_rgThreadState.front().m_pDiffItem;
56         std::vector<ThreadState>::iterator it = m_rgThreadState.begin();
57         while (it != m_rgThreadState.end())
58         {
59                 const DIFFITEM *di = it->m_pDiffItem;
60                 if (di != nullptr && (di->diffcode.diffcode & DIFFCODE::COMPAREFLAGS) == DIFFCODE::NOCMP)
61                 {
62                         int nHitCount = it->m_nHitCount++;
63                         if (nHitCountMax < nHitCount)
64                         {
65                                 nHitCountMax = nHitCount;
66                                 cdi = di;
67                         }
68                 }
69                 ++it;
70         }
71         return cdi;
72 }
73
74 /** 
75  * @brief Reset comparestats.
76  * Use this function to reset stats before new compare.
77  */
78 void CompareStats::Reset()
79 {
80         std::fill(std::begin(m_counts), std::end(m_counts), 0);
81         SetCompareState(STATE_IDLE);
82         m_nTotalItems = 0;
83         m_nComparedItems = 0;
84         m_bCompareDone = false;
85 }
86
87 /** 
88  * @brief Change compare state.
89  * @param [in] state New compare state.
90  */
91 void CompareStats::SetCompareState(CompareStats::CMP_STATE state)
92 {
93         // New compare starting so reset ready status
94         if (state == STATE_START)
95                 m_bCompareDone = false;
96         // Compare ready
97         if (state == STATE_IDLE && m_state == STATE_COMPARE)
98                 m_bCompareDone = true;
99
100         m_state = state;
101 }
102
103 /** 
104  * @brief Convert diffcode to compare-result.
105  * @param [in] diffcode DIFFITEM.diffcode to convert.
106  * @return Compare result.
107  */
108 CompareStats::RESULT CompareStats::GetResultFromCode(unsigned diffcode) const
109 {
110         DIFFCODE di(diffcode);
111         
112         bool is_dir = di.isDirectory();
113         // Test first for skipped so we pick all skipped items as such 
114         if (di.isResultFiltered())
115         {
116                 // skipped
117                 return is_dir ? RESULT_DIRSKIP : RESULT_SKIP;
118         }
119         else if (di.isSideFirstOnly())
120         {
121                 // left-only
122                 return is_dir ? RESULT_LDIRUNIQUE : RESULT_LUNIQUE;
123         }
124         else if (di.isSideSecondOnly())
125         {
126                 // right-only
127                 if (is_dir)
128                         return (m_nDirs < 3) ? RESULT_RDIRUNIQUE : RESULT_MDIRUNIQUE;
129                 else
130                         return (m_nDirs < 3) ? RESULT_RUNIQUE : RESULT_MUNIQUE;
131         }
132         else if (di.isSideThirdOnly())
133         {
134                 // right-only
135                 return is_dir ? RESULT_RDIRUNIQUE : RESULT_RUNIQUE;
136         }
137         else if (m_nDirs > 2)
138         {
139                 switch (diffcode & DIFFCODE::ALL)
140                 {
141                 case (DIFFCODE::SECOND | DIFFCODE::THIRD) : return is_dir ? RESULT_LDIRMISSING : RESULT_LMISSING;
142                 case (DIFFCODE::FIRST  | DIFFCODE::THIRD) : return is_dir ? RESULT_MDIRMISSING : RESULT_MMISSING;
143                 case (DIFFCODE::FIRST  | DIFFCODE::SECOND): return is_dir ? RESULT_RDIRMISSING : RESULT_RMISSING;
144                 }
145         }
146         if (di.isResultError())
147         {
148                 // could be directory error ?
149                 return RESULT_ERROR;
150         }
151         // Now we know it was on both sides & compared!
152         else if (di.isResultSame())
153         {
154                 // same
155                 if (is_dir)
156                 {
157                         return RESULT_DIRSAME;
158                 }
159                 else
160                 {
161                         return di.isBin() ? RESULT_BINSAME : RESULT_SAME;
162                 }
163         }
164         else
165         {
166                 if (is_dir)
167                 {
168                         return RESULT_DIRDIFF;
169                 }
170                 else
171                 {
172                         // presumably it is different
173                         return di.isBin() ? RESULT_BINDIFF : RESULT_DIFF;
174                 }
175         }
176 }
177
178 void CompareStats::Swap(int idx1, int idx2)
179 {
180         idx2 = m_nDirs < 3 ? idx2 + 1 : idx2;
181         m_counts[RESULT_LUNIQUE     + idx2] = m_counts[RESULT_LUNIQUE     + idx1].exchange(m_counts[RESULT_LUNIQUE     + idx2]);
182         m_counts[RESULT_LMISSING    + idx2] = m_counts[RESULT_LMISSING    + idx1].exchange(m_counts[RESULT_LMISSING    + idx2]);
183         m_counts[RESULT_LDIRUNIQUE  + idx2] = m_counts[RESULT_LDIRUNIQUE  + idx1].exchange(m_counts[RESULT_LDIRUNIQUE  + idx2]);
184         m_counts[RESULT_LDIRMISSING + idx2] = m_counts[RESULT_LDIRMISSING + idx1].exchange(m_counts[RESULT_LDIRMISSING + idx2]);
185 }