Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
308
libs/tracking/archive.hpp
Normal file
308
libs/tracking/archive.hpp
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
#pragma once
|
||||
|
||||
#include "traffic/speed_groups.hpp"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
#include "coding/point_coding.hpp"
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/varint.hpp"
|
||||
#include "coding/writer.hpp"
|
||||
#include "coding/zlib.hpp"
|
||||
|
||||
#include "base/checked_cast.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-copy"
|
||||
#endif
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace tracking
|
||||
{
|
||||
namespace helpers
|
||||
{
|
||||
struct Restrictions
|
||||
{
|
||||
static double const kMinDeltaLat;
|
||||
static double const kMaxDeltaLat;
|
||||
static double const kMinDeltaLon;
|
||||
static double const kMaxDeltaLon;
|
||||
};
|
||||
|
||||
struct Limits
|
||||
{
|
||||
double m_minLat;
|
||||
double m_maxLat;
|
||||
double m_minLon;
|
||||
double m_maxLon;
|
||||
};
|
||||
|
||||
Limits GetLimits(bool isDelta);
|
||||
} // namespace helpers
|
||||
|
||||
struct Packet
|
||||
{
|
||||
Packet();
|
||||
explicit Packet(location::GpsInfo const & info);
|
||||
Packet(double lat, double lon, uint32_t timestamp);
|
||||
|
||||
double m_lat;
|
||||
double m_lon;
|
||||
uint32_t m_timestamp;
|
||||
};
|
||||
|
||||
struct PacketCar : Packet
|
||||
{
|
||||
PacketCar();
|
||||
PacketCar(location::GpsInfo const & info, traffic::SpeedGroup const & speedGroup);
|
||||
PacketCar(double lat, double lon, uint32_t timestamp, traffic::SpeedGroup speed);
|
||||
|
||||
traffic::SpeedGroup m_speedGroup;
|
||||
};
|
||||
|
||||
template <typename Pack>
|
||||
class BasicArchive
|
||||
{
|
||||
public:
|
||||
BasicArchive(size_t maxSize, double minDelaySeconds);
|
||||
|
||||
template <typename Writer>
|
||||
bool Write(Writer & dst);
|
||||
|
||||
template <typename Reader>
|
||||
bool Read(Reader & src);
|
||||
|
||||
template <typename... PackParameters>
|
||||
bool Add(PackParameters &&... params);
|
||||
|
||||
size_t Size() const;
|
||||
bool ReadyToDump() const;
|
||||
std::vector<Pack> Extract() const;
|
||||
|
||||
private:
|
||||
boost::circular_buffer<Pack> m_buffer;
|
||||
double const m_minDelaySeconds;
|
||||
};
|
||||
|
||||
// Abstract packet traits.
|
||||
template <typename Pack>
|
||||
struct TraitsPacket
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct TraitsPacket<Packet>
|
||||
{
|
||||
static size_t constexpr kCoordBits = 32;
|
||||
|
||||
template <typename Writer>
|
||||
static void Write(Writer & writer, Packet const & packet, bool isDelta)
|
||||
{
|
||||
auto const lim = helpers::GetLimits(isDelta);
|
||||
|
||||
WriteVarUint(writer, DoubleToUint32(packet.m_lat, lim.m_minLat, lim.m_maxLat, kCoordBits));
|
||||
WriteVarUint(writer, DoubleToUint32(packet.m_lon, lim.m_minLon, lim.m_maxLon, kCoordBits));
|
||||
WriteVarUint(writer, packet.m_timestamp);
|
||||
}
|
||||
|
||||
template <typename Reader>
|
||||
static Packet Read(Reader & src, bool isDelta)
|
||||
{
|
||||
auto const lim = helpers::GetLimits(isDelta);
|
||||
|
||||
double const lat = Uint32ToDouble(ReadVarUint<uint32_t>(src), lim.m_minLat, lim.m_maxLat, kCoordBits);
|
||||
double const lon = Uint32ToDouble(ReadVarUint<uint32_t>(src), lim.m_minLon, lim.m_maxLon, kCoordBits);
|
||||
uint32_t const timestamp = ReadVarUint<uint32_t>(src);
|
||||
return Packet(lat, lon, timestamp);
|
||||
}
|
||||
|
||||
static Packet GetDelta(Packet const & current, Packet const & previous)
|
||||
{
|
||||
uint32_t const deltaTimestamp = current.m_timestamp - previous.m_timestamp;
|
||||
double const deltaLat = current.m_lat - previous.m_lat;
|
||||
double const deltaLon = current.m_lon - previous.m_lon;
|
||||
return Packet(deltaLat, deltaLon, deltaTimestamp);
|
||||
}
|
||||
|
||||
static Packet Combine(Packet const & previous, Packet const & delta)
|
||||
{
|
||||
double const lat = previous.m_lat + delta.m_lat;
|
||||
double const lon = previous.m_lon + delta.m_lon;
|
||||
uint32_t const timestamp = previous.m_timestamp + delta.m_timestamp;
|
||||
return Packet(lat, lon, timestamp);
|
||||
}
|
||||
|
||||
static traffic::SpeedGroup GetSpeedGroup(Packet const & packet) { return traffic::SpeedGroup::Unknown; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TraitsPacket<PacketCar>
|
||||
{
|
||||
template <typename Writer>
|
||||
static void Write(Writer & writer, PacketCar const & packet, bool isDelta)
|
||||
{
|
||||
TraitsPacket<Packet>::Write(writer, packet, isDelta);
|
||||
static_assert(std::is_same<uint8_t, std::underlying_type_t<decltype(packet.m_speedGroup)>>::value, "");
|
||||
WriteVarUint(writer, static_cast<uint8_t>(packet.m_speedGroup));
|
||||
}
|
||||
|
||||
template <typename Reader>
|
||||
static PacketCar Read(Reader & src, bool isDelta)
|
||||
{
|
||||
Packet const base = TraitsPacket<Packet>::Read(src, isDelta);
|
||||
auto const speedGroup = static_cast<traffic::SpeedGroup>(ReadPrimitiveFromSource<uint8_t>(src));
|
||||
return PacketCar(base.m_lat, base.m_lon, base.m_timestamp, speedGroup);
|
||||
}
|
||||
|
||||
static PacketCar GetDelta(PacketCar const & current, PacketCar const & previous)
|
||||
{
|
||||
Packet const delta = TraitsPacket<Packet>::GetDelta(current, previous);
|
||||
return PacketCar(delta.m_lat, delta.m_lon, delta.m_timestamp, current.m_speedGroup);
|
||||
}
|
||||
|
||||
static PacketCar Combine(PacketCar const & previous, PacketCar const & delta)
|
||||
{
|
||||
Packet const base = TraitsPacket<Packet>::Combine(previous, delta);
|
||||
return PacketCar(base.m_lat, base.m_lon, base.m_timestamp, delta.m_speedGroup);
|
||||
}
|
||||
|
||||
static traffic::SpeedGroup GetSpeedGroup(PacketCar const & packet) { return packet.m_speedGroup; }
|
||||
};
|
||||
|
||||
template <typename Reader>
|
||||
std::vector<uint8_t> InflateToBuffer(Reader & src)
|
||||
{
|
||||
std::vector<uint8_t> deflatedBuf(base::checked_cast<size_t>(src.Size()));
|
||||
src.Read(deflatedBuf.data(), deflatedBuf.size());
|
||||
|
||||
coding::ZLib::Inflate inflate(coding::ZLib::Inflate::Format::ZLib);
|
||||
std::vector<uint8_t> buffer;
|
||||
inflate(deflatedBuf.data(), deflatedBuf.size(), std::back_inserter(buffer));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void DeflateToDst(Writer & dst, std::vector<uint8_t> const & buf)
|
||||
{
|
||||
coding::ZLib::Deflate deflate(coding::ZLib::Deflate::Format::ZLib, coding::ZLib::Deflate::Level::BestCompression);
|
||||
std::vector<uint8_t> deflatedBuf;
|
||||
deflate(buf.data(), buf.size(), std::back_inserter(deflatedBuf));
|
||||
dst.Write(deflatedBuf.data(), deflatedBuf.size());
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
BasicArchive<Pack>::BasicArchive(size_t maxSize, double minDelaySeconds)
|
||||
: m_buffer(maxSize)
|
||||
, m_minDelaySeconds(minDelaySeconds)
|
||||
{}
|
||||
|
||||
template <typename Pack>
|
||||
template <typename... PackParameters>
|
||||
bool BasicArchive<Pack>::Add(PackParameters &&... params)
|
||||
{
|
||||
Pack newPacket = Pack(std::forward<PackParameters>(params)...);
|
||||
if (!m_buffer.empty() && newPacket.m_timestamp < m_buffer.back().m_timestamp + m_minDelaySeconds)
|
||||
return false;
|
||||
|
||||
m_buffer.push_back(std::move(newPacket));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
size_t BasicArchive<Pack>::Size() const
|
||||
{
|
||||
return m_buffer.size();
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
bool BasicArchive<Pack>::ReadyToDump() const
|
||||
{
|
||||
return m_buffer.full();
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
std::vector<Pack> BasicArchive<Pack>::Extract() const
|
||||
{
|
||||
std::vector<Pack> res;
|
||||
res.reserve(m_buffer.size());
|
||||
res.insert(res.end(), m_buffer.begin(), m_buffer.end());
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
template <typename Writer>
|
||||
bool BasicArchive<Pack>::Write(Writer & dst)
|
||||
{
|
||||
if (m_buffer.empty())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
MemWriter<std::vector<uint8_t>> writer(buf);
|
||||
// For aggregating tracks we use two-step approach: at first we delta-code the coordinates and
|
||||
// timestamps; then we use coding::ZLib::Inflate to compress data.
|
||||
TraitsPacket<Pack>::Write(writer, m_buffer[0], false /* isDelta */);
|
||||
|
||||
for (size_t i = 1; i < m_buffer.size(); ++i)
|
||||
{
|
||||
Pack const delta = TraitsPacket<Pack>::GetDelta(m_buffer[i], m_buffer[i - 1]);
|
||||
TraitsPacket<Pack>::Write(writer, delta, true /* isDelta */);
|
||||
}
|
||||
|
||||
DeflateToDst(dst, buf);
|
||||
|
||||
LOG(LDEBUG, ("Dumped to disk", m_buffer.size(), "items"));
|
||||
|
||||
m_buffer.clear();
|
||||
return true;
|
||||
}
|
||||
catch (std::exception const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Error writing to file", e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Pack>
|
||||
template <typename Reader>
|
||||
bool BasicArchive<Pack>::Read(Reader & src)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const buffer = InflateToBuffer(src);
|
||||
ReaderSource<MemReaderWithExceptions> reader(MemReaderWithExceptions(buffer.data(), buffer.size()));
|
||||
if (reader.Size() == 0)
|
||||
return false;
|
||||
|
||||
m_buffer.clear();
|
||||
|
||||
// Read first point.
|
||||
m_buffer.push_back(TraitsPacket<Pack>::Read(reader, false /* isDelta */));
|
||||
|
||||
// Read with delta.
|
||||
while (reader.Size() > 0)
|
||||
{
|
||||
Pack const delta = TraitsPacket<Pack>::Read(reader, true /* isDelta */);
|
||||
m_buffer.push_back(TraitsPacket<Pack>::Combine(m_buffer.back(), delta));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (std::exception const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Error reading file", e.what()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace tracking
|
||||
Loading…
Add table
Add a link
Reference in a new issue