Skip to content

Commit

Permalink
* Code cleanup
Browse files Browse the repository at this point in the history
* Documentation
  • Loading branch information
tim-weis committed May 25, 2022
1 parent ec1cf19 commit 4497134
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 82 deletions.
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
Standard: c++20
TabWidth: 8
UseTab: Never
...
Expand Down
3 changes: 1 addition & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ indent_size = 4
[*.{h,hpp,cpp}]
trim_trailing_whitespace = true
insert_final_newline = true
guidelines = 120
guidelines_style = 1px dotted ffcccccc
guidelines = 80 1px dotted ff666666, 120 1px dotted ffcccccc
27 changes: 21 additions & 6 deletions char_encoding_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
#include <string_view>


inline auto to_utf8(::std::wstring_view const utf16_str)
//! \brief Re-encodes a UTF-16 encoded string into a UTF-8 encoded string.
//!
//! \param[in] utf16_str A string view into a UTF-16 encoded string.
//!
//! \return A UTF-8 encoded string equivalent to the provided input. This
//! function fails with an exception in case the input isn't well-formed
//! UTF-8.
//!
[[nodiscard]] inline auto to_utf8(::std::wstring_view const utf16_str)
{
auto const len_required { ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16_str.data(),
static_cast<int>(utf16_str.length()), nullptr, 0, nullptr,
Expand All @@ -21,23 +29,30 @@ inline auto to_utf8(::std::wstring_view const utf16_str)
auto const bytes_written { ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16_str.data(),
static_cast<int>(utf16_str.length()), utf8.data(),
static_cast<int>(utf8.length()), nullptr, nullptr) };
assert(bytes_written == len_required);
THROW_LAST_ERROR_IF(bytes_written != len_required);

return utf8;
}


inline auto to_utf16(::std::string_view const utf8_str)
//! \brief Re-encodes a UTF-8 encoded string into a UTF-16 encoded string.
//!
//! \param[in] utf8_str A string view into a UTF-8 encoded string.
//!
//! \return A UTF-16 encoded string equivalent to the provided input. This
//! function fails with an exception in case the input isn't well-formed
//! UTF-16.
//!
[[nodiscard]] inline auto to_utf16(::std::string_view const utf8_str)
{
auto const len_required { ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_str.data(),
static_cast<int>(utf8_str.length()), nullptr, 0) };
THROW_LAST_ERROR_IF(len_required == 0);

::std::wstring utf16(len_required, '\0');
::std::wstring utf16(len_required, L'\0');
auto const bytes_written { ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8_str.data(),
static_cast<int>(utf8_str.length()), utf16.data(),
static_cast<int>(utf16.length())) };
assert(bytes_written == len_required);
THROW_LAST_ERROR_IF(bytes_written != len_required);

return utf16;
}
4 changes: 2 additions & 2 deletions control_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <string>


inline ::std::wstring wnd_class_name(HWND const hwnd)
[[nodiscard]] inline ::std::wstring wnd_class_name(HWND const hwnd)
{
wchar_t buffer[128] {};
auto const chars_written { ::RealGetWindowClassW(hwnd, buffer, ARRAYSIZE(buffer)) };
Expand All @@ -19,7 +19,7 @@ inline ::std::wstring wnd_class_name(HWND const hwnd)
}


inline bool is_list_view(HWND const hwnd) { return wnd_class_name(hwnd) == WC_LISTVIEWW; }
[[nodiscard]] inline bool is_list_view(HWND const hwnd) { return wnd_class_name(hwnd) == WC_LISTVIEWW; }


inline void list_view_clear_selection(HWND const list_view)
Expand Down
14 changes: 7 additions & 7 deletions date_time_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@
#include <cstdint>


constexpr auto invalid_filetime() noexcept
[[nodiscard]] consteval inline auto invalid_filetime() noexcept
{
return ::FILETIME { .dwLowDateTime = 0xFFFFFFFF, .dwHighDateTime = 0xFFFFFFFF };
}


constexpr auto operator==(::FILETIME const lhs, ::FILETIME const rhs) noexcept
[[nodiscard]] constexpr inline auto operator==(::FILETIME const lhs, ::FILETIME const rhs) noexcept
{
return (lhs.dwLowDateTime == rhs.dwLowDateTime) && (lhs.dwHighDateTime == rhs.dwHighDateTime);
}


// Converts a time point to a filetime value. Month and day are 1-based; hour, minute, and second are 0-based.
auto to_filetime(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute, uint16_t second)
[[nodiscard]] inline auto to_filetime(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uint16_t minute,
uint16_t second)
{
::SYSTEMTIME const st {
.wYear = year, .wMonth = month, .wDay = day, .wHour = hour, .wMinute = minute, .wSecond = second
Expand All @@ -34,14 +35,13 @@ auto to_filetime(uint16_t year, uint16_t month, uint16_t day, uint16_t hour, uin
}


constexpr auto to_uint(::FILETIME const ft) noexcept
[[nodiscard]] constexpr inline auto to_uint(::FILETIME const ft) noexcept
{
::ULARGE_INTEGER uli { .LowPart = ft.dwLowDateTime, .HighPart = ft.dwHighDateTime };
return uint64_t { uli.QuadPart };
return (static_cast<uint64_t>(ft.dwHighDateTime) << 32) | static_cast<uint64_t>(ft.dwLowDateTime);
}


auto to_systemtime(::FILETIME const ft)
[[nodiscard]] inline auto to_systemtime(::FILETIME const ft)
{
::SYSTEMTIME st {};
THROW_IF_WIN32_BOOL_FALSE(::FileTimeToSystemTime(&ft, &st));
Expand Down
100 changes: 59 additions & 41 deletions display_utils.h
Original file line number Diff line number Diff line change
@@ -1,65 +1,83 @@
#pragma once

#include "date_time_utils.h"
#include "model.h"

#include <Windows.h>

#include <cassert>
#include <iomanip>
#include <format>
#include <optional>
#include <sstream>
#include <span>
#include <string>


namespace
//! \brief Creates a human readable string representation for a timestamp value
//! according to [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601).
//!
//! \param[in] timestamp The timestamp value to format. This value is assumed to
//! be in UTC.
//!
//! \return The string representation of the given timestamp value down to
//! millisecond precision.
//!
[[nodiscard]] inline ::std::wstring to_iso8601(::FILETIME const& timestamp)
{
auto const st { to_systemtime(timestamp) };

wchar_t to_hex_char(unsigned char value) { return value > 9u ? value - 10u + L'A' : value + L'0'; }

} // namespace


inline ::std::wstring format_timestamp(::FILETIME const& timestamp)
{
::SYSTEMTIME st {};
::FileTimeToSystemTime(&timestamp, &st);

::std::wostringstream oss {};

oss << std::setfill(L'0') << std::setw(4) << st.wYear << L"-" << std::setfill(L'0') << std::setw(2) << st.wMonth
<< L"-" << std::setfill(L'0') << std::setw(2) << st.wDay << L" " << std::setfill(L'0') << std::setw(2)
<< st.wHour << L":" << std::setfill(L'0') << std::setw(2) << st.wMinute << L":" << std::setfill(L'0')
<< std::setw(2) << st.wSecond << L"." << std::setfill(L'0') << std::setw(3) << st.wMilliseconds;

return oss.str();
return ::std::format(L"{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.{:03d}Z", st.wYear, st.wMonth, st.wDay, st.wHour,
st.wMinute, st.wSecond, st.wMilliseconds);
}

inline ::std::wstring to_hex_string(unsigned char const data)
//! \brief Converts a byte value into its hexadecimal string representation.
//!
//! \param[in] value The byte value to convert.
//!
//! \return The hexadecimal string representation of the byte value.
//!
//! \remark This function uses uppercase hex digits. The result is zero-padded
//! in case the byte value is less than 16. It isn't otherwise prefixed
//! (e.g. with `0x`), and the returned string is guaranteed to be of
//! length 2.
//!
[[nodiscard]] inline constexpr ::std::wstring to_hex_string(unsigned char const value)
{
::std::wstring result(2, L'\0');

result[0] = ::to_hex_char(data >> 4);
result[1] = ::to_hex_char(data & 0xF);
constexpr auto to_hex_digit = [](unsigned char const value) noexcept -> wchar_t {
constexpr auto& digits = L"0123456789ABCDEF";
return digits[value & 0xF];
};

return result;
return { to_hex_digit(value >> 4), to_hex_digit(value & 0xF) };
}

inline ::std::wstring to_hex_string(unsigned char const* data, size_t length)
//! \brief Converts a byte buffer into its hexadecimal string representation.
//!
//! \param[in] data A view into the byte buffer to convert. This span may be
//! empty.
//!
//! \return If the input designates an emtpy span, this function returns an
//! empty string. Otherwise, this function returns a string where each
//! byte is represented by two hexadecimal digits. Individual bytes are
//! delimited by a space character.
//!
[[nodiscard]] inline constexpr ::std::wstring to_hex_string(::std::span<unsigned char const> const data)
{
assert(length > 0);

// Fill result with space characters
::std::wstring result(length * 3 - 1, L' ');
::std::wstring result {};

size_t src_index { 0 };
while (src_index < length)
if (data.size() > 0)
{
auto const value { data[src_index] };
auto dest_index { src_index * 3 };
result[dest_index] = ::to_hex_char(value >> 4);
result[dest_index + 1] = ::to_hex_char(value & 0xF);

++src_index;
// Reserve enough room up front; 2 hex digits per value plus a delimiter
// (except for the final one)
result.reserve(data.size() * 3 - 1);
for (auto const value : data)
{
// Append delimiter unless this is the first value
if (!result.empty())
{
result.append(L" ");
}
result.append(to_hex_string(value));
}
}

return result;
Expand All @@ -83,7 +101,7 @@ inline ::std::optional<::std::wstring> details_from_packet(::data_proxy const& p
assert(el.size == sizeof(::FILETIME));
auto const& ft { *reinterpret_cast<::FILETIME const*>(packet.data() + packet.header_size()
+ el.offset) };
ret += ::format_timestamp(ft);
ret += ::to_iso8601(ft);
}
break;

Expand Down
17 changes: 13 additions & 4 deletions log_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,28 @@
#include <cstdint>


/// Returns timestamp recorded as the first entry in a sensor log capture.
inline FILETIME get_start_timestamp(wchar_t const* path_name)
//! \brief Returns the timestamp of a sensor log file.
//!
//! \param[in] path_name Fully qualified path name to the sensor log file.
//!
//! \return The timestamp when recording into the provided sensor log file
//! started. The timestamp is (presumably) in UTC as observed by the MS
//! Band device.
//!
[[nodiscard]] inline FILETIME get_start_timestamp(wchar_t const* path_name)
{
wil::unique_hfile f { ::CreateFileW(path_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!f.is_valid());
// Skip first 2 bytes
::SetFilePointer(f.get(), 2, nullptr, FILE_BEGIN);
// Skip first 2 bytes (packet type and length)
THROW_LAST_ERROR_IF(::SetFilePointer(f.get(), 2, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER);

uint64_t timestamp {};
DWORD bytes_read {};
THROW_IF_WIN32_BOOL_FALSE(
::ReadFile(f.get(), reinterpret_cast<char*>(&timestamp), sizeof(timestamp), &bytes_read, nullptr));
THROW_LAST_ERROR_IF(bytes_read != sizeof(timestamp));

FILETIME const ft { .dwLowDateTime = static_cast<DWORD>(timestamp),
.dwHighDateTime = static_cast<DWORD>(timestamp >> 32) };

Expand Down
25 changes: 14 additions & 11 deletions model.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@ struct data_proxy
data_proxy(unsigned char const* begin, unsigned char const* end) : begin_ { begin }, end_ { end } {}
data_proxy(data_proxy const&) = default;

constexpr auto header_size() const noexcept { return sizeof(unsigned char) + sizeof(unsigned char); }
auto payload_size() const noexcept { return ::std::distance(begin_, end_) - header_size(); }
auto data() const noexcept { return begin_; };
[[nodiscard]] static consteval size_t header_size() noexcept
{
return sizeof(unsigned char) + sizeof(unsigned char);
}
[[nodiscard]] auto payload_size() const noexcept { return ::std::distance(begin_, end_) - header_size(); }
[[nodiscard]] auto data() const noexcept { return begin_; };
// Return typed value at specific offset. The offset is relative to the payload.
template <typename T>
std::add_const_t<T> value(size_t const offset) const noexcept
[[nodiscard]] std::add_const_t<T> value(size_t const offset) const noexcept
{
assert(offset + sizeof(T) <= payload_size());
return *reinterpret_cast<std::add_const_t<T>*>(begin_ + /*header_size()*/ 2 + offset);
return *reinterpret_cast<std::add_const_t<T>*>(begin_ + header_size() + offset);
}
auto type() const noexcept { return *begin_; }
[[nodiscard]] auto type() const noexcept { return *begin_; }

private:
unsigned char const* begin_;
Expand Down Expand Up @@ -94,7 +97,7 @@ struct raw_data
}
}

auto const& directory() const noexcept { return directory_; }
[[nodiscard]] auto const& directory() const noexcept { return directory_; }

private:
// std::wstring path_name_;
Expand Down Expand Up @@ -239,7 +242,7 @@ struct model
}

// Returns packet at index applying the current sort map
auto const& packet(size_t const index) const noexcept
[[nodiscard]] auto const& packet(size_t const index) const noexcept
{
assert(index < sort_map_.size());
auto const mapped_index { sort_map_[index] };
Expand All @@ -248,17 +251,17 @@ struct model
}

// Returns the mapped index (after filtering and sorting is applied)
auto packet_index(size_t const index) const noexcept
[[nodiscard]] auto packet_index(size_t const index) const noexcept
{
assert(index < sort_map_.size());
return sort_map_[index];
}

auto packet_count() const noexcept { return sort_map_.size(); }
[[nodiscard]] auto packet_count() const noexcept { return sort_map_.size(); }

// auto& data() noexcept { return data_; }
// auto const& data() const noexcept { return data_; }
auto const& packet_descriptions() const noexcept { return packet_descriptions_; }
[[nodiscard]] auto const& packet_descriptions() const noexcept { return packet_descriptions_; }

// Apply sorting
// Defaults to natural sorting (sequential order as in the raw binary data)
Expand Down
8 changes: 4 additions & 4 deletions msbsla.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ void render_graph(HDC const hdc, RECT const& rect, COLORREF const color, model c
{
// Find min/max values
auto [min_it, max_it] { ::std::minmax_element(begin(indexes), end(indexes),
[& m = m, offset](auto const lhs, auto const rhs) {
[&m = m, offset](auto const lhs, auto const rhs) {
auto const val_lhs { m.packet(lhs).value<T>(offset) };
auto const val_rhs { m.packet(rhs).value<T>(offset) };

Expand Down Expand Up @@ -679,8 +679,8 @@ INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM l
break;

case packet_col::payload: {
auto payload_str { ::to_hex_string(g_spModel->packet(item_index).data() + 2,
g_spModel->packet(item_index).payload_size()) };
auto payload_str { ::to_hex_string(
{ g_spModel->packet(item_index).data() + 2, g_spModel->packet(item_index).payload_size() }) };
// Truncate payload if it exceeds available space.
if (payload_str.size() >= nmlvdi.item.cchTextMax)
{
Expand Down Expand Up @@ -755,7 +755,7 @@ INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM l
}

case 1: {
auto const text { format_timestamp(info.timestamp) };
auto const text { to_iso8601(info.timestamp) };
::wcsncpy_s(nmlvdi.item.pszText, nmlvdi.item.cchTextMax, text.c_str(), text.length());
nmlvdi.item.mask |= LVIF_DI_SETITEM;
break;
Expand Down
Loading

0 comments on commit 4497134

Please sign in to comment.