Index: src/libchcore/TSpeedTracker.cpp =================================================================== diff -u -N -r2fe97a93f21771d75901d4b6559057d1ea055104 -re96806b7f8ff7ca7e9f4afbea603e6351a3dc3e3 --- src/libchcore/TSpeedTracker.cpp (.../TSpeedTracker.cpp) (revision 2fe97a93f21771d75901d4b6559057d1ea055104) +++ src/libchcore/TSpeedTracker.cpp (.../TSpeedTracker.cpp) (revision e96806b7f8ff7ca7e9f4afbea603e6351a3dc3e3) @@ -8,236 +8,235 @@ #include #include "TStringArray.h" -BEGIN_CHCORE_NAMESPACE - -TSpeedTracker::TSpeedTracker(unsigned long long ullTrackTime, unsigned long long ullSampleTime) : - m_stRequiredSamples(ullSampleTime ? boost::numeric_cast(ullTrackTime / ullSampleTime) : 0), - m_ullSampleTime(ullSampleTime), - m_dSamplesPerSecond(ullSampleTime != 0 ? 1000.0 / ullSampleTime : 0.0), - m_dPartialSpeedNotInSamples(0), - m_ullTimeIntervalNotInSamples(0), - m_stNextSamplePos(0), - m_ullLastTimestamp(std::numeric_limits::max()), - m_ullZeroIntervalData(0) +namespace chcore { - if(m_ullSampleTime == 0 || m_stRequiredSamples == 0) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); - std::fill_n(std::inserter(m_vSamples, m_vSamples.end()), m_stRequiredSamples, 0.0); -} - -void TSpeedTracker::Clear() -{ - m_dPartialSpeedNotInSamples = 0; - m_ullTimeIntervalNotInSamples = 0; - m_stNextSamplePos = 0; - m_ullLastTimestamp = std::numeric_limits::max(); - m_ullZeroIntervalData = 0; - std::fill(m_vSamples.begin(), m_vSamples.end(), 0.0); -} - -void TSpeedTracker::AddSample(unsigned long long ullValue, unsigned long long ullTimestamp) -{ - // if this is the first sample ever added (after construction or after clear) then - // we don't have time interval yet - just remember the timestamp and ignore value - if(m_ullLastTimestamp == std::numeric_limits::max()) + TSpeedTracker::TSpeedTracker(unsigned long long ullTrackTime, unsigned long long ullSampleTime) : + m_stRequiredSamples(ullSampleTime ? boost::numeric_cast(ullTrackTime / ullSampleTime) : 0), + m_ullSampleTime(ullSampleTime), + m_dSamplesPerSecond(ullSampleTime != 0 ? 1000.0 / ullSampleTime : 0.0), + m_dPartialSpeedNotInSamples(0), + m_ullTimeIntervalNotInSamples(0), + m_stNextSamplePos(0), + m_ullLastTimestamp(std::numeric_limits::max()), + m_ullZeroIntervalData(0) { - m_ullLastTimestamp = ullTimestamp; - return; + if (m_ullSampleTime == 0 || m_stRequiredSamples == 0) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + std::fill_n(std::inserter(m_vSamples, m_vSamples.end()), m_stRequiredSamples, 0.0); } - // sanity check - make sure the data is valid - if(ullTimestamp < m_ullLastTimestamp) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); - - // calculate the interval since the time last sample was added - unsigned long long ullInterval = ullTimestamp - m_ullLastTimestamp; - m_ullLastTimestamp = ullTimestamp; - - if(ullInterval == 0) // special case 0: if interval is 0 - put the data sample somewhere for future use + void TSpeedTracker::Clear() { - m_ullZeroIntervalData += ullValue; - return; - } - else if(ullInterval >= m_ullSampleTime * m_stRequiredSamples) // special case 1: interval is bigger than what we track - { - m_stNextSamplePos = 0; - m_dPartialSpeedNotInSamples = 0.0; + m_dPartialSpeedNotInSamples = 0; m_ullTimeIntervalNotInSamples = 0; + m_stNextSamplePos = 0; + m_ullLastTimestamp = std::numeric_limits::max(); m_ullZeroIntervalData = 0; - - double dSpeed = NormalizeValueByTime(ullValue, ullInterval, m_ullSampleTime); - std::fill(m_vSamples.begin(), m_vSamples.end(), dSpeed); - return; + std::fill(m_vSamples.begin(), m_vSamples.end(), 0.0); } - else + + void TSpeedTracker::AddSample(unsigned long long ullValue, unsigned long long ullTimestamp) { - // append the data from previous zero-interval samples - ullValue += m_ullZeroIntervalData; - m_ullZeroIntervalData = 0; - } + // if this is the first sample ever added (after construction or after clear) then + // we don't have time interval yet - just remember the timestamp and ignore value + if (m_ullLastTimestamp == std::numeric_limits::max()) + { + m_ullLastTimestamp = ullTimestamp; + return; + } - // calculate speed - double dSpeed = NormalizeValueByTime(ullValue, ullInterval, m_ullSampleTime); + // sanity check - make sure the data is valid + if (ullTimestamp < m_ullLastTimestamp) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); - // finalize the incomplete sample and adjust the input data - FinalizeIncompleteSample(dSpeed, ullInterval); + // calculate the interval since the time last sample was added + unsigned long long ullInterval = ullTimestamp - m_ullLastTimestamp; + m_ullLastTimestamp = ullTimestamp; - // deal with the full samples - AddCompleteSamples(dSpeed, ullInterval); + if (ullInterval == 0) // special case 0: if interval is 0 - put the data sample somewhere for future use + { + m_ullZeroIntervalData += ullValue; + return; + } + else if (ullInterval >= m_ullSampleTime * m_stRequiredSamples) // special case 1: interval is bigger than what we track + { + m_stNextSamplePos = 0; + m_dPartialSpeedNotInSamples = 0.0; + m_ullTimeIntervalNotInSamples = 0; + m_ullZeroIntervalData = 0; - // and finally prepare the incomplete sample data for future use - PrepareIncompleteSample(ullInterval, dSpeed); -} - -double TSpeedTracker::GetSpeed() const -{ - double dResult = 0.0; - - if(m_ullTimeIntervalNotInSamples != 0) - { - dResult = CalculateIncompleteSampleNormalizedSpeed(); - - for(size_t stIndex = 0; stIndex < m_vSamples.size(); ++stIndex) + double dSpeed = NormalizeValueByTime(ullValue, ullInterval, m_ullSampleTime); + std::fill(m_vSamples.begin(), m_vSamples.end(), dSpeed); + return; + } + else { - if(stIndex != m_stNextSamplePos) - dResult += m_vSamples[stIndex]; + // append the data from previous zero-interval samples + ullValue += m_ullZeroIntervalData; + m_ullZeroIntervalData = 0; } - } - else - dResult = std::accumulate(m_vSamples.begin(), m_vSamples.end(), 0.0); - return dResult / m_vSamples.size() * m_dSamplesPerSecond; -} + // calculate speed + double dSpeed = NormalizeValueByTime(ullValue, ullInterval, m_ullSampleTime); -void TSpeedTracker::AppendSamples(double dSpeed, size_t stSamplesCount) -{ - if(m_vSamples.size() != m_stRequiredSamples) - THROW_CORE_EXCEPTION(eErr_InternalProblem); + // finalize the incomplete sample and adjust the input data + FinalizeIncompleteSample(dSpeed, ullInterval); - stSamplesCount = std::min(stSamplesCount, m_stRequiredSamples); - while(stSamplesCount--) - { - m_vSamples[GetNextSampleIndexAndIncrease()] = dSpeed; + // deal with the full samples + AddCompleteSamples(dSpeed, ullInterval); + + // and finally prepare the incomplete sample data for future use + PrepareIncompleteSample(ullInterval, dSpeed); } -} -size_t TSpeedTracker::GetNextSampleIndexAndIncrease() -{ - size_t stResult = m_stNextSamplePos++; - if(m_stNextSamplePos >= m_vSamples.size()) - m_stNextSamplePos = 0; - return stResult; -} + double TSpeedTracker::GetSpeed() const + { + double dResult = 0.0; -double TSpeedTracker::NormalizeValueByTime(unsigned long long ullValue, unsigned long long ullTime, unsigned long long ullNormalizeTime) -{ - return Math::Div64(ullNormalizeTime, ullTime) * ullValue; -} + if (m_ullTimeIntervalNotInSamples != 0) + { + dResult = CalculateIncompleteSampleNormalizedSpeed(); -void TSpeedTracker::FinalizeIncompleteSample(double dSpeed, unsigned long long& ullInterval) -{ - if(m_ullTimeIntervalNotInSamples == 0 || m_dPartialSpeedNotInSamples == 0.0 || ullInterval == 0) - return; + for (size_t stIndex = 0; stIndex < m_vSamples.size(); ++stIndex) + { + if (stIndex != m_stNextSamplePos) + dResult += m_vSamples[stIndex]; + } + } + else + dResult = std::accumulate(m_vSamples.begin(), m_vSamples.end(), 0.0); - // how much data do we need? - unsigned long long ullIntervalStillNeeded = m_ullSampleTime - m_ullTimeIntervalNotInSamples; - if(ullInterval < ullIntervalStillNeeded) - { - // we can only add the next partial sample, but cannot finalize - m_ullTimeIntervalNotInSamples += ullInterval; - m_dPartialSpeedNotInSamples += dSpeed * Math::Div64(ullInterval, m_ullSampleTime); - ullInterval = 0; + return dResult / m_vSamples.size() * m_dSamplesPerSecond; } - else + + void TSpeedTracker::AppendSamples(double dSpeed, size_t stSamplesCount) { - // going to finalize sample - m_dPartialSpeedNotInSamples += dSpeed * Math::Div64(ullIntervalStillNeeded, m_ullSampleTime); + if (m_vSamples.size() != m_stRequiredSamples) + THROW_CORE_EXCEPTION(eErr_InternalProblem); - m_vSamples[GetNextSampleIndexAndIncrease()] = m_dPartialSpeedNotInSamples; - ullInterval -= ullIntervalStillNeeded; + stSamplesCount = std::min(stSamplesCount, m_stRequiredSamples); + while (stSamplesCount--) + { + m_vSamples[GetNextSampleIndexAndIncrease()] = dSpeed; + } + } - m_dPartialSpeedNotInSamples = 0.0; - m_ullTimeIntervalNotInSamples = 0; + size_t TSpeedTracker::GetNextSampleIndexAndIncrease() + { + size_t stResult = m_stNextSamplePos++; + if (m_stNextSamplePos >= m_vSamples.size()) + m_stNextSamplePos = 0; + return stResult; } -} -void TSpeedTracker::AddCompleteSamples(double dSpeed, unsigned long long& ullInterval) -{ - size_t stSamplesCount = boost::numeric_cast(std::min(ullInterval / m_ullSampleTime, (unsigned long long)m_stRequiredSamples)); - - // fill the container with full samples - while(stSamplesCount--) + double TSpeedTracker::NormalizeValueByTime(unsigned long long ullValue, unsigned long long ullTime, unsigned long long ullNormalizeTime) { - m_vSamples[GetNextSampleIndexAndIncrease()] = dSpeed; + return Math::Div64(ullNormalizeTime, ullTime) * ullValue; } - ullInterval = ullInterval % m_ullSampleTime; -} + void TSpeedTracker::FinalizeIncompleteSample(double dSpeed, unsigned long long& ullInterval) + { + if (m_ullTimeIntervalNotInSamples == 0 || m_dPartialSpeedNotInSamples == 0.0 || ullInterval == 0) + return; -double TSpeedTracker::CalculateIncompleteSampleNormalizedSpeed() const -{ - // get the speed for incomplete sample - double dIncompleteSamplePercentage = Math::Div64(m_ullTimeIntervalNotInSamples, m_ullSampleTime); - double dResult = m_dPartialSpeedNotInSamples + (1.0 - dIncompleteSamplePercentage) * m_vSamples[m_stNextSamplePos]; + // how much data do we need? + unsigned long long ullIntervalStillNeeded = m_ullSampleTime - m_ullTimeIntervalNotInSamples; + if (ullInterval < ullIntervalStillNeeded) + { + // we can only add the next partial sample, but cannot finalize + m_ullTimeIntervalNotInSamples += ullInterval; + m_dPartialSpeedNotInSamples += dSpeed * Math::Div64(ullInterval, m_ullSampleTime); + ullInterval = 0; + } + else + { + // going to finalize sample + m_dPartialSpeedNotInSamples += dSpeed * Math::Div64(ullIntervalStillNeeded, m_ullSampleTime); - return dResult; -} + m_vSamples[GetNextSampleIndexAndIncrease()] = m_dPartialSpeedNotInSamples; + ullInterval -= ullIntervalStillNeeded; -void TSpeedTracker::PrepareIncompleteSample(unsigned long long ullInterval, double dSpeed) -{ - if(ullInterval > 0) + m_dPartialSpeedNotInSamples = 0.0; + m_ullTimeIntervalNotInSamples = 0; + } + } + + void TSpeedTracker::AddCompleteSamples(double dSpeed, unsigned long long& ullInterval) { - // we can only add the next partial sample, but cannot finalize - m_ullTimeIntervalNotInSamples = ullInterval; - m_dPartialSpeedNotInSamples = dSpeed * Math::Div64(ullInterval, m_ullSampleTime); + size_t stSamplesCount = boost::numeric_cast(std::min(ullInterval / m_ullSampleTime, (unsigned long long)m_stRequiredSamples)); + + // fill the container with full samples + while (stSamplesCount--) + { + m_vSamples[GetNextSampleIndexAndIncrease()] = dSpeed; + } + + ullInterval = ullInterval % m_ullSampleTime; } -} -TString TSpeedTracker::ToString() const -{ - TString strData; - - strData += boost::lexical_cast(m_stNextSamplePos).c_str(); - strData += _T(";"); + double TSpeedTracker::CalculateIncompleteSampleNormalizedSpeed() const + { + // get the speed for incomplete sample + double dIncompleteSamplePercentage = Math::Div64(m_ullTimeIntervalNotInSamples, m_ullSampleTime); + double dResult = m_dPartialSpeedNotInSamples + (1.0 - dIncompleteSamplePercentage) * m_vSamples[m_stNextSamplePos]; - strData += boost::lexical_cast(m_dPartialSpeedNotInSamples).c_str(); - strData += _T(";"); - strData += boost::lexical_cast(m_ullTimeIntervalNotInSamples).c_str(); - strData += _T(";"); - strData += boost::lexical_cast(m_ullZeroIntervalData).c_str(); - strData += _T(";"); + return dResult; + } - BOOST_FOREACH(double dVal, m_vSamples) + void TSpeedTracker::PrepareIncompleteSample(unsigned long long ullInterval, double dSpeed) { - strData += boost::lexical_cast(dVal).c_str(); - strData += _T(";"); + if (ullInterval > 0) + { + // we can only add the next partial sample, but cannot finalize + m_ullTimeIntervalNotInSamples = ullInterval; + m_dPartialSpeedNotInSamples = dSpeed * Math::Div64(ullInterval, m_ullSampleTime); + } } - strData.TrimRightSelf(_T(";")); + TString TSpeedTracker::ToString() const + { + TString strData; - return strData; -} + strData += boost::lexical_cast(m_stNextSamplePos).c_str(); + strData += _T(";"); -void TSpeedTracker::FromString(const TString& strData) -{ - TStringArray arrStrings; - strData.Split(_T(";"), arrStrings); + strData += boost::lexical_cast(m_dPartialSpeedNotInSamples).c_str(); + strData += _T(";"); + strData += boost::lexical_cast(m_ullTimeIntervalNotInSamples).c_str(); + strData += _T(";"); + strData += boost::lexical_cast(m_ullZeroIntervalData).c_str(); + strData += _T(";"); - const size_t SerializedMembers = 4; - if(arrStrings.GetCount() != m_stRequiredSamples + SerializedMembers) - THROW_CORE_EXCEPTION(eErr_InvalidArgument); + BOOST_FOREACH(double dVal, m_vSamples) + { + strData += boost::lexical_cast(dVal).c_str(); + strData += _T(";"); + } - Clear(); + strData.TrimRightSelf(_T(";")); - m_stNextSamplePos = boost::lexical_cast(arrStrings.GetAt(0).c_str()); - m_dPartialSpeedNotInSamples = boost::lexical_cast(arrStrings.GetAt(1).c_str()); - m_ullTimeIntervalNotInSamples = boost::lexical_cast(arrStrings.GetAt(2).c_str()); - m_ullZeroIntervalData = boost::lexical_cast((PCTSTR)arrStrings.GetAt(3).c_str()); + return strData; + } - for(size_t stIndex = 4; stIndex < arrStrings.GetCount(); ++stIndex) + void TSpeedTracker::FromString(const TString& strData) { - m_vSamples[stIndex - 4] = boost::lexical_cast(arrStrings.GetAt(stIndex).c_str()); + TStringArray arrStrings; + strData.Split(_T(";"), arrStrings); + + const size_t SerializedMembers = 4; + if (arrStrings.GetCount() != m_stRequiredSamples + SerializedMembers) + THROW_CORE_EXCEPTION(eErr_InvalidArgument); + + Clear(); + + m_stNextSamplePos = boost::lexical_cast(arrStrings.GetAt(0).c_str()); + m_dPartialSpeedNotInSamples = boost::lexical_cast(arrStrings.GetAt(1).c_str()); + m_ullTimeIntervalNotInSamples = boost::lexical_cast(arrStrings.GetAt(2).c_str()); + m_ullZeroIntervalData = boost::lexical_cast((PCTSTR)arrStrings.GetAt(3).c_str()); + + for (size_t stIndex = 4; stIndex < arrStrings.GetCount(); ++stIndex) + { + m_vSamples[stIndex - 4] = boost::lexical_cast(arrStrings.GetAt(stIndex).c_str()); + } } } - -END_CHCORE_NAMESPACE