Allow searching for raw variants
This makes the visitor a little bit more complicated but it allows client code to fetch raw variants. It is useful when dealing with arrays and maps, so that client code can decide to cache the intermediate array or map into a variable and then run subsequent searches on that variant rather than from the start. It should make looping a bit less expensive.
This commit is contained in:
parent
9fb7dd8537
commit
3e2cfb3b37
3 changed files with 107 additions and 35 deletions
12
src/main.cpp
12
src/main.cpp
|
@ -64,7 +64,13 @@ int main(int argc, const char* argv[]) {
|
|||
auto hashes = duck::collect_hashes(values);
|
||||
std::cout << "Got " << hashes.size() << " hashes\n";
|
||||
|
||||
const auto file_count = static_cast<std::int_fast32_t>(duck::find_int("/info/files/[[size]]", values));
|
||||
const auto variant_array = duck::find_variant("/info/files", values);
|
||||
if (not variant_array) {
|
||||
std::cout << "No object found in torrent file at path /info/files\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto file_count = static_cast<std::int_fast32_t>(duck::find_int("/[[size]]", *variant_array));
|
||||
if (file_count)
|
||||
std::cout << "Input has " << file_count << " file entries\n";
|
||||
else
|
||||
|
@ -99,13 +105,13 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
std::string search("/info/files/[[");
|
||||
std::string search("/[[");
|
||||
std::size_t hash_index = 0;
|
||||
std::size_t match_count = 0;
|
||||
std::size_t read_size = 0;
|
||||
std::vector<std::uint8_t> buff;
|
||||
for (std::int_fast32_t z = 0; z < file_count; ++z) {
|
||||
auto file_name = std::string{duck::find_string(search + std::to_string(z) + "]]/path/[[0]]", values)};
|
||||
auto file_name = std::string{duck::find_string(search + std::to_string(z) + "]]/path/[[0]]", *variant_array)};
|
||||
std::cout << "path index " << z << '\t' << file_name << '\n';
|
||||
|
||||
std::ifstream istream(file_name, std::ios::in|std::ios::binary);
|
||||
|
|
|
@ -18,11 +18,18 @@
|
|||
#include "find_t_visitor.hpp"
|
||||
#include "split.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <cassert>
|
||||
|
||||
namespace duck::detail {
|
||||
namespace {
|
||||
template <typename T>
|
||||
void assert_same_value (const TorrentValue& var, const T& val) {
|
||||
assert(boost::get<T>(&var) != nullptr and *boost::get<T>(&var) == val);
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
template <typename T>
|
||||
FindTVisitor<T>::FindTVisitor (std::string_view search_path) {
|
||||
auto split = dincore::split(search_path, '/', true, true);
|
||||
|
@ -33,9 +40,12 @@ FindTVisitor<T>::FindTVisitor (std::string_view search_path) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void FindTVisitor<T>::reset() {
|
||||
void FindTVisitor<T>::reset (const TorrentValue* curr_variant) {
|
||||
m_search_error = false;
|
||||
m_search_match_count = 0;
|
||||
|
||||
m_curr_variant = curr_variant;
|
||||
assert(m_curr_variant);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -44,27 +54,23 @@ bool FindTVisitor<T>::has_error() const noexcept {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
T FindTVisitor<T>::operator() (TorrentIntType value) {
|
||||
if constexpr (std::is_same<TorrentIntType, T>::value)
|
||||
return value;
|
||||
m_search_error = true;
|
||||
return {};
|
||||
auto FindTVisitor<T>::operator() (TorrentIntType value) -> TRet {
|
||||
return scalar_operator_impl(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T FindTVisitor<T>::operator() (const TorrentStringType& value) {
|
||||
if constexpr (std::is_same<TorrentStringType, T>::value) {
|
||||
if (is_path_found())
|
||||
return value;
|
||||
auto FindTVisitor<T>::operator() (const TorrentStringType& value) -> TRet {
|
||||
return scalar_operator_impl(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto FindTVisitor<T>::operator() (const std::vector<TorrentValue>& values) -> TRet {
|
||||
if (is_path_found()) {
|
||||
if constexpr (std::is_same<TorrentValue, T>::value)
|
||||
return std::cref(*m_curr_variant);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
m_search_error = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T FindTVisitor<T>::operator() (const std::vector<TorrentValue>& values) {
|
||||
if (is_path_found())
|
||||
return {};
|
||||
|
||||
if constexpr (std::is_same<TorrentIntType, T>::value) {
|
||||
if (m_search[m_search_match_count] == "[[size]]")
|
||||
|
@ -77,17 +83,24 @@ T FindTVisitor<T>::operator() (const std::vector<TorrentValue>& values) {
|
|||
if (matched) {
|
||||
++m_search_match_count;
|
||||
const auto index = static_cast<std::size_t>(std::stoul(match[1]));
|
||||
if (index < values.size())
|
||||
if (index < values.size()) {
|
||||
m_curr_variant = &values[index];
|
||||
return boost::apply_visitor(*this, values[index]);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T FindTVisitor<T>::operator() (const std::map<TorrentStringType, TorrentValue>& value) {
|
||||
auto FindTVisitor<T>::operator() (const std::map<TorrentStringType, TorrentValue>& value) -> TRet {
|
||||
if (is_path_found()) {
|
||||
m_search_error = true;
|
||||
return {};
|
||||
if constexpr (std::is_same<TorrentValue, T>::value) {
|
||||
return std::cref(*m_curr_variant);
|
||||
}
|
||||
else {
|
||||
m_search_error = true;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
auto it_found = value.find(m_search[m_search_match_count]);
|
||||
|
@ -95,9 +108,25 @@ T FindTVisitor<T>::operator() (const std::map<TorrentStringType, TorrentValue>&
|
|||
return {};
|
||||
|
||||
++m_search_match_count;
|
||||
m_curr_variant = &it_found->second;
|
||||
return boost::apply_visitor(*this, it_found->second);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
auto FindTVisitor<T>::scalar_operator_impl (const U& value) -> TRet {
|
||||
if constexpr (std::is_same<TorrentValue, T>::value) {
|
||||
assert_same_value(*m_curr_variant, value);
|
||||
return std::cref(*m_curr_variant);
|
||||
}
|
||||
else if constexpr (std::is_same<U, T>::value) {
|
||||
if (is_path_found())
|
||||
return value;
|
||||
}
|
||||
m_search_error = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool FindTVisitor<T>::is_path_found() const {
|
||||
return m_search.size() == m_search_match_count;
|
||||
|
@ -105,4 +134,5 @@ bool FindTVisitor<T>::is_path_found() const {
|
|||
|
||||
template class FindTVisitor<TorrentStringType>;
|
||||
template class FindTVisitor<TorrentIntType>;
|
||||
template class FindTVisitor<TorrentValue>;
|
||||
} //namespace duck::detail
|
||||
|
|
|
@ -23,25 +23,36 @@
|
|||
#include <boost/variant/apply_visitor.hpp>
|
||||
#include <vector>
|
||||
#include <ciso646>
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
|
||||
namespace duck {
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
class FindTVisitor : boost::static_visitor<T> {
|
||||
public:
|
||||
typedef typename std::conditional<std::is_same<T, TorrentValue>::value,
|
||||
std::optional< std::reference_wrapper<const T> >,
|
||||
T
|
||||
>::type TRet;
|
||||
|
||||
FindTVisitor (std::string_view search_path);
|
||||
|
||||
void reset();
|
||||
void reset (const TorrentValue* curr_variant);
|
||||
bool has_error() const noexcept;
|
||||
T operator() (TorrentIntType value);
|
||||
T operator() (const TorrentStringType& value);
|
||||
T operator() (const std::vector<TorrentValue>&);
|
||||
T operator() (const std::map<TorrentStringType, TorrentValue>& value);
|
||||
TRet operator() (TorrentIntType value);
|
||||
TRet operator() (const TorrentStringType& value);
|
||||
TRet operator() (const std::vector<TorrentValue>&);
|
||||
TRet operator() (const std::map<TorrentStringType, TorrentValue>& value);
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
TRet scalar_operator_impl (const U& value);
|
||||
|
||||
bool is_path_found() const;
|
||||
|
||||
std::vector<std::string> m_search;
|
||||
const TorrentValue* m_curr_variant;
|
||||
std::size_t m_search_match_count{0};
|
||||
bool m_search_error{false};
|
||||
};
|
||||
|
@ -51,15 +62,24 @@ typedef detail::FindTVisitor<TorrentStringType> FindStringVisitor;
|
|||
typedef detail::FindTVisitor<TorrentIntType> FindIntVisitor;
|
||||
|
||||
template <typename T>
|
||||
inline T find_item(std::string_view path, const std::vector<TorrentValue>& values) {
|
||||
inline auto find_item(std::string_view path, const std::vector<TorrentValue>& values) {
|
||||
typedef typename detail::FindTVisitor<T>::TRet TRet;
|
||||
|
||||
detail::FindTVisitor<T> visitor(path);
|
||||
for (const auto& value : values) {
|
||||
visitor.reset();
|
||||
T found = boost::apply_visitor(visitor, value);
|
||||
visitor.reset(&value);
|
||||
TRet found = boost::apply_visitor(visitor, value);
|
||||
if (not visitor.has_error())
|
||||
return found;
|
||||
}
|
||||
return {};
|
||||
return TRet{};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline auto find_item(std::string_view path, const TorrentValue& value) {
|
||||
detail::FindTVisitor<T> visitor(path);
|
||||
visitor.reset(&value);
|
||||
return boost::apply_visitor(visitor, value);
|
||||
}
|
||||
|
||||
inline TorrentIntType find_int(std::string_view path, const std::vector<TorrentValue>& values) {
|
||||
|
@ -69,4 +89,20 @@ inline TorrentIntType find_int(std::string_view path, const std::vector<TorrentV
|
|||
inline TorrentStringType find_string(std::string_view path, const std::vector<TorrentValue>& values) {
|
||||
return find_item<TorrentStringType>(path, values);
|
||||
}
|
||||
|
||||
inline auto find_variant(std::string_view path, const std::vector<TorrentValue>& values) {
|
||||
return find_item<TorrentValue>(path, values);
|
||||
}
|
||||
|
||||
inline TorrentIntType find_int(std::string_view path, const TorrentValue& value) {
|
||||
return find_item<TorrentIntType>(path, value);
|
||||
}
|
||||
|
||||
inline TorrentStringType find_string(std::string_view path, const TorrentValue& value) {
|
||||
return find_item<TorrentStringType>(path, value);
|
||||
}
|
||||
|
||||
inline auto find_variant(std::string_view path, const TorrentValue& value) {
|
||||
return find_item<TorrentValue>(path, value);
|
||||
}
|
||||
} //namespace duck
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue