@@ -5,6 +5,7 @@ | |||
#include <list> | |||
#include <vector> | |||
#include "Misc.h" | |||
#include "Nullable.h" | |||
#include "Exception.h" | |||
#include "MetaProgramming.h" | |||
@@ -49,87 +50,11 @@ namespace linq | |||
using mp_range_value_type = typename utl::mp_remove_ref<T>::value_type; | |||
/* helper types **************************************************************************/ | |||
template<class T> | |||
struct wrapper | |||
{ | |||
using value_type = T; | |||
value_type value; | |||
inline value_type operator*() const | |||
{ return value; } | |||
inline wrapper& operator=(const wrapper& other) | |||
{ | |||
value = other.value; | |||
return *this; | |||
} | |||
inline wrapper& operator=(wrapper&& other) | |||
{ | |||
value = std::move(other).value; | |||
return *this; | |||
} | |||
template<class X> | |||
inline wrapper(X&& v) : | |||
value(std::forward<X>(v)) | |||
{ } | |||
inline wrapper(const value_type& v) : | |||
value(v) | |||
{ } | |||
inline wrapper(const wrapper& other) : | |||
value(other.value) | |||
{ } | |||
inline wrapper(wrapper&& other) : | |||
value(std::move(other.value)) | |||
{ } | |||
}; | |||
template<class T> | |||
struct wrapper<T&> | |||
{ | |||
using value_type = T&; | |||
using storage_type = T*; | |||
storage_type value; | |||
inline value_type operator*() const | |||
{ return *value; } | |||
inline wrapper& operator=(const wrapper& other) | |||
{ | |||
value = other.value; | |||
return *this; | |||
} | |||
inline wrapper& operator=(wrapper&& other) | |||
{ | |||
value = std::move(other.value); | |||
return *this; | |||
} | |||
inline wrapper(value_type v) : | |||
value(&v) | |||
{ } | |||
inline wrapper(const wrapper& other) : | |||
value(other.value) | |||
{ } | |||
inline wrapper(wrapper&& other) : | |||
value(std::move(other.value)) | |||
{ } | |||
}; | |||
template<class T, class TPredicate> | |||
struct op_wrapper_less | |||
{ | |||
using predicate_type = TPredicate; | |||
using value_type = wrapper<T>; | |||
using value_type = utl::wrapper<T>; | |||
predicate_type predicate; | |||
@@ -194,24 +119,19 @@ namespace linq | |||
using clean_key_type = utl::mp_remove_ref<key_type>; | |||
using value_type = TValue; | |||
using this_type = lookup<key_type, value_type>; | |||
using wrapped_key_type = wrapper<key_type>; | |||
using wrapped_value_type = wrapper<value_type>; | |||
using wrapped_key_type = utl::wrapper<key_type>; | |||
using wrapped_value_type = utl::wrapper<value_type>; | |||
using keys_value_type = std::pair<wrapped_key_type, size_t>; | |||
using keys_type = std::vector<keys_value_type>; | |||
using values_type = std::vector<wrapped_value_type>; | |||
using range_indices_type = std::pair<size_t, size_t>; | |||
private: | |||
struct lookup_range; | |||
struct lookup_key_value_range; | |||
using lookup_range_wrapper = range_wrapper<lookup_range>; | |||
using lookup_key_value_range_wrapper = range_wrapper<lookup_key_value_range>; | |||
public: | |||
using range_type = lookup_key_value_range_wrapper; | |||
private: | |||
struct lookup_range : public tag_range | |||
{ | |||
using value_type = lookup::value_type; | |||
@@ -223,10 +143,10 @@ namespace linq | |||
Finished, | |||
}; | |||
const values_type& values; | |||
size_t current; | |||
size_t end; | |||
State state; | |||
values_type& values; | |||
size_t current; | |||
size_t end; | |||
State state; | |||
inline value_type& front() | |||
{ | |||
@@ -258,7 +178,7 @@ namespace linq | |||
} | |||
} | |||
inline lookup_range(const values_type& v, size_t c, size_t e) : | |||
inline lookup_range(values_type& v, size_t c, size_t e) : | |||
values (v), | |||
current (c), | |||
end (e), | |||
@@ -273,10 +193,10 @@ namespace linq | |||
{ LINQ_COPY_CTOR(); } | |||
inline lookup_range(lookup_range&& other) : | |||
values (std::move(other.values)), | |||
current (std::move(other.current)), | |||
end (std::move(other.end)), | |||
state (std::move(other.state)) | |||
values (std::move(other).values), | |||
current (std::move(other).current), | |||
end (std::move(other).end), | |||
state (std::move(other).state) | |||
{ LINQ_MOVE_CTOR(); } | |||
inline ~lookup_range() | |||
@@ -562,8 +482,9 @@ namespace linq | |||
return (current != std::end(container)); | |||
} | |||
inline container_range(container_type& c) noexcept : | |||
container (c), | |||
template<class C> | |||
inline container_range(C&& c) noexcept : | |||
container (std::forward<C>(c)), | |||
initialized (false) | |||
{ LINQ_CTOR(); } | |||
@@ -737,8 +658,8 @@ namespace linq | |||
template<class T> | |||
struct __impl_make_inner_range | |||
{ | |||
using iterator_type = decltype(std::begin(std::declval<T>())); | |||
using type = iterator_range<iterator_type>; | |||
using container_type = T; | |||
using type = container_range<container_type>; | |||
}; | |||
template<class T> | |||
@@ -762,13 +683,13 @@ namespace linq | |||
template<class T> | |||
inline typename std::enable_if<std::is_base_of<tag_range, T>::value>::type | |||
build_inner_range(T value) | |||
build_inner_range(T&& value) | |||
{ inner_range = value; } | |||
template<class T> | |||
inline typename std::enable_if<!std::is_base_of<tag_range, T>::value>::type | |||
build_inner_range(T value) | |||
{ inner_range = inner_range_type(std::begin(value), std::end(value)); } | |||
build_inner_range(T&& value) | |||
{ inner_range = inner_range_type(std::forward<T>(value)); } | |||
inline value_type& front() | |||
{ | |||
@@ -824,7 +745,7 @@ namespace linq | |||
using less_predicate_type = TLessPredicate; | |||
using this_type = order_by_range<range_type, select_predicate_type, less_predicate_type>; | |||
using value_type = mp_range_value_type<range_type>; | |||
using wrapped_value_type = wrapper<value_type>; | |||
using wrapped_value_type = utl::wrapper<value_type>; | |||
using vector_type = std::vector<wrapped_value_type>; | |||
range_type range; | |||
@@ -858,7 +779,7 @@ namespace linq | |||
this->select_predicate(*l), | |||
this->select_predicate(*r)); | |||
}); | |||
current = 0; | |||
return true; | |||
} | |||
@@ -904,7 +825,7 @@ namespace linq | |||
using less_predicate_type = TLessPredicate; | |||
using this_type = distinct_range<range_type, less_predicate_type>; | |||
using value_type = mp_range_value_type<range_type>; | |||
using set_value_type = wrapper<value_type>; | |||
using set_value_type = utl::wrapper<value_type>; | |||
using set_less_type = op_wrapper_less<value_type, less_predicate_type>; | |||
using set_type = std::set<set_value_type, set_less_type>; | |||
@@ -1277,7 +1198,7 @@ namespace linq | |||
inline auto build(TRange&& range) | |||
{ | |||
using range_value_type = mp_range_value_type<TRange>; | |||
using value_type = utl::mp_remove_ref<range_value_type>; | |||
using value_type = utl::mp_remove_const<utl::mp_remove_ref<range_value_type>>; | |||
using vector_type = std::vector<value_type>; | |||
vector_type ret; | |||
@@ -1418,11 +1339,11 @@ namespace linq | |||
struct op_select_key_default | |||
{ | |||
template<class TKey, class TValue> | |||
inline auto operator()(std::pair<TKey, TValue>& p) | |||
inline auto operator()(std::pair<TKey, TValue> p) | |||
{ return p.first; } | |||
template<class TKey, class TValue> | |||
inline auto operator()(std::tuple<TKey, TValue>& t) | |||
inline auto operator()(std::tuple<TKey, TValue> t) | |||
{ return std::get<0>(t); } | |||
template<class T> | |||
@@ -1433,11 +1354,11 @@ namespace linq | |||
struct op_select_value_default | |||
{ | |||
template<class TKey, class TValue> | |||
inline auto operator()(std::pair<TKey, TValue>& p) | |||
inline auto operator()(std::pair<TKey, TValue> p) | |||
{ return p.second; } | |||
template<class TKey, class TValue> | |||
inline auto operator()(std::tuple<TKey, TValue>& t) | |||
inline auto operator()(std::tuple<TKey, TValue> t) | |||
{ return std::get<1>(t); } | |||
template<class T> | |||
@@ -1570,4 +1491,10 @@ namespace linq | |||
inline auto to_lookup() | |||
{ return to_lookup(std::move(op_select_key_default()), std::move(op_select_value_default())); } | |||
template <class TKey, class TValue> | |||
using lookup_value_range_type = typename __impl::lookup<TKey, TValue>::lookup_range_wrapper; | |||
template <class TKey, class TValue> | |||
using lookup_key_value_range_type = typename __impl::lookup<TKey, TValue>::lookup_key_value_range_wrapper; | |||
} |
@@ -3,6 +3,17 @@ | |||
#include <cxxabi.h> | |||
#include <iostream> | |||
#if defined(__linux__) | |||
# include <endian.h> | |||
#elif defined(__FreeBSD__) || defined(__NetBSD__) | |||
# include <sys/endian.h> | |||
#elif defined(__OpenBSD__) | |||
# include <sys/types.h> | |||
# define be16toh(x) betoh16(x) | |||
# define be32toh(x) betoh32(x) | |||
# define be64toh(x) betoh64(x) | |||
#endif | |||
namespace utl | |||
{ | |||
@@ -19,6 +30,104 @@ namespace utl | |||
} | |||
}; | |||
/* simple class that stores a value of type T */ | |||
template<class T> | |||
struct wrapper | |||
{ | |||
using value_type = T; | |||
value_type value; | |||
inline value_type& operator*() | |||
{ return value; } | |||
inline const value_type& operator*() const | |||
{ return value; } | |||
inline wrapper& operator=(const value_type v) | |||
{ | |||
value = v; | |||
return *this; | |||
} | |||
inline wrapper& operator=(const wrapper& other) | |||
{ | |||
value = other.value; | |||
return *this; | |||
} | |||
inline wrapper& operator=(wrapper&& other) | |||
{ | |||
value = std::move(other).value; | |||
return *this; | |||
} | |||
inline wrapper() : | |||
value(value_type()) | |||
{ } | |||
inline wrapper(const value_type& v) : | |||
value(v) | |||
{ } | |||
inline wrapper(const wrapper& other) : | |||
value(other.value) | |||
{ } | |||
inline wrapper(wrapper&& other) : | |||
value(std::move(other.value)) | |||
{ } | |||
}; | |||
template<class T> | |||
struct wrapper<T&> | |||
{ | |||
using value_type = T&; | |||
using storage_type = T*; | |||
storage_type value; | |||
inline value_type operator*() const | |||
{ | |||
assert(value != nullptr); | |||
return *value; | |||
} | |||
inline wrapper& operator=(const value_type v) | |||
{ | |||
value = &v; | |||
return *this; | |||
} | |||
inline wrapper& operator=(const wrapper& other) | |||
{ | |||
value = other.value; | |||
return *this; | |||
} | |||
inline wrapper& operator=(wrapper&& other) | |||
{ | |||
value = std::move(other.value); | |||
return *this; | |||
} | |||
inline wrapper() : | |||
value(nullptr) | |||
{ } | |||
inline wrapper(value_type v) : | |||
value(&v) | |||
{ } | |||
inline wrapper(const wrapper& other) : | |||
value(other.value) | |||
{ } | |||
inline wrapper(wrapper&& other) : | |||
value(std::move(other.value)) | |||
{ } | |||
}; | |||
/* Helper Methods ****************************************************************************/ | |||
inline int bitCount(uint32_t u) | |||
{ | |||
@@ -29,12 +138,27 @@ namespace utl | |||
} | |||
template<class T, class S> | |||
bool tryCast(T* t, S*& s) | |||
inline bool tryCast(T* t, S*& s) | |||
{ | |||
s = dynamic_cast<S*>(t); | |||
return static_cast<bool>(s); | |||
} | |||
namespace __impl | |||
{ | |||
template<class T, size_t N = sizeof(T)> | |||
struct network_convert_helper; | |||
} | |||
template<class T> | |||
inline T hton(const T& value) | |||
{ return __impl::network_convert_helper<T>::hton(value); } | |||
template<class T> | |||
inline T ntoh(const T& value) | |||
{ return __impl::network_convert_helper<T>::ntoh(value); } | |||
/* Indent Stream *****************************************************************************/ | |||
namespace __impl | |||
{ | |||
@@ -67,4 +191,47 @@ namespace utl | |||
return os; | |||
} | |||
/* implementation ****************************************************************************/ | |||
namespace __impl | |||
{ | |||
template<class T> | |||
struct network_convert_helper<T, 1> | |||
{ | |||
static inline T hton(const T& t) | |||
{ return t; } | |||
static inline T ntoh(const T& t) | |||
{ return t; } | |||
}; | |||
template<class T> | |||
struct network_convert_helper<T, 2> | |||
{ | |||
static inline T hton(const T& t) | |||
{ return reinterpret_cast<T>(htobe16(reinterpret_cast<uint16_t>(t))); } | |||
static inline T ntoh(const T& t) | |||
{ return reinterpret_cast<T>(be16toh(reinterpret_cast<uint16_t>(t))); } | |||
}; | |||
template<class T> | |||
struct network_convert_helper<T, 4> | |||
{ | |||
static inline T hton(const T& t) | |||
{ return reinterpret_cast<T>(htobe32(reinterpret_cast<uint32_t>(t))); } | |||
static inline T ntoh(const T& t) | |||
{ return reinterpret_cast<T>(be32toh(reinterpret_cast<uint32_t>(t))); } | |||
}; | |||
template<class T> | |||
struct network_convert_helper<T, 8> | |||
{ | |||
static inline T hton(const T& t) | |||
{ return reinterpret_cast<T>(htobe64(reinterpret_cast<uint64_t>(t))); } | |||
static inline T ntoh(const T& t) | |||
{ return reinterpret_cast<T>(be64toh(reinterpret_cast<uint64_t>(t))); } | |||
}; | |||
} | |||
} |
@@ -0,0 +1,122 @@ | |||
#include <gtest/gtest.h> | |||
#include "../src/cpputils/StringHelper.h" | |||
#include "../src/cpputils/HandleManager.h" | |||
using namespace utl; | |||
using HandleManagerInt = utl::HandleManager<int>; | |||
TEST(HandleManagerTest, fromString_toString) | |||
{ | |||
Handle handle; | |||
EXPECT_FALSE(tryFromString("11-22-3344-5566778", handle)); | |||
EXPECT_TRUE (tryFromString("11-22-3344-55667788", handle)); | |||
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle)); | |||
EXPECT_TRUE (tryFromString("1122-3344-55667788", handle)); | |||
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle)); | |||
EXPECT_TRUE (tryFromString("11-223344-55667788", handle)); | |||
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle)); | |||
EXPECT_TRUE (tryFromString("11-22-334455667788", handle)); | |||
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle)); | |||
EXPECT_TRUE (tryFromString("1122334455667788", handle)); | |||
EXPECT_EQ (std::string("11-22-3344-55667788"), toString(handle)); | |||
} | |||
TEST(HandleManagerTest, insert) | |||
{ | |||
HandleManagerInt manager; | |||
auto handle = manager.insert(0, 0, 123); | |||
EXPECT_TRUE(static_cast<bool>(handle)); | |||
} | |||
TEST(HandleManagerTest, remove) | |||
{ | |||
HandleManagerInt manager; | |||
auto handle = manager.insert(0, 0, 123); | |||
EXPECT_FALSE(manager.remove(156161)); | |||
EXPECT_FALSE(manager.remove(1136)); | |||
EXPECT_FALSE(manager.remove(627624)); | |||
EXPECT_FALSE(manager.remove(0)); | |||
EXPECT_TRUE (manager.remove(handle)); | |||
} | |||
TEST(HandleManagerTest, clear) | |||
{ | |||
HandleManagerInt manager; | |||
auto handle1 = manager.insert(0, 0, 123); | |||
manager.clear(); | |||
auto handle2 = manager.insert(0, 0, 555); | |||
EXPECT_EQ(handle1, handle2); | |||
} | |||
TEST(HandleManagerTest, isValid) | |||
{ | |||
HandleManagerInt manager; | |||
EXPECT_FALSE(manager.isValid(0)); | |||
EXPECT_FALSE(manager.isValid(123)); | |||
EXPECT_FALSE(manager.isValid(51627)); | |||
EXPECT_FALSE(manager.isValid(1513)); | |||
EXPECT_FALSE(manager.isValid(16621)); | |||
auto handle = manager.insert(0, 0, 123); | |||
EXPECT_TRUE(manager.isValid(handle)); | |||
} | |||
TEST(HandleManagerTest, tryGet) | |||
{ | |||
int val; | |||
HandleManagerInt manager; | |||
EXPECT_FALSE(manager.tryGet(123, val)); | |||
EXPECT_FALSE(manager.tryGet(5132, val)); | |||
EXPECT_FALSE(manager.tryGet(6216, val)); | |||
EXPECT_FALSE(manager.tryGet(15616724, val)); | |||
EXPECT_FALSE(manager.tryGet(12353, val)); | |||
auto handle = manager.insert(1, 2, 555); | |||
EXPECT_TRUE(manager.tryGet(handle, val)); | |||
EXPECT_EQ (555, val); | |||
} | |||
TEST(HandleManagerTest, get) | |||
{ | |||
int val; | |||
HandleManagerInt manager; | |||
EXPECT_ANY_THROW(manager.get(123)); | |||
EXPECT_ANY_THROW(manager.get(5132)); | |||
EXPECT_ANY_THROW(manager.get(6216)); | |||
EXPECT_ANY_THROW(manager.get(15616724)); | |||
EXPECT_ANY_THROW(manager.get(12353)); | |||
auto handle = manager.insert(1, 2, 555); | |||
EXPECT_EQ(555, manager.get(handle)); | |||
} | |||
TEST(HandleManagerTest, update) | |||
{ | |||
int val; | |||
HandleManagerInt manager; | |||
EXPECT_FALSE(manager.update(123, 555)); | |||
EXPECT_FALSE(manager.update(5132, 555)); | |||
EXPECT_FALSE(manager.update(6216, 555)); | |||
EXPECT_FALSE(manager.update(15616724, 555)); | |||
EXPECT_FALSE(manager.update(12353, 555)); | |||
auto handle = manager.insert(1, 2, 555); | |||
EXPECT_TRUE(manager.update(handle, 554)); | |||
EXPECT_EQ (554, manager.get(handle)); | |||
} | |||
TEST(HandleManagerTest, set) | |||
{ | |||
HandleManagerInt manager; | |||
auto handle = fromString<utl::Handle>("00-00-0001-00000000"); | |||
EXPECT_TRUE (manager.set(handle, 555)); | |||
EXPECT_EQ (555, manager.get(handle)); | |||
handle = fromString<utl::Handle>("00-00-0001-00000000"); | |||
EXPECT_TRUE (manager.set(handle, 554)); | |||
EXPECT_EQ (554, manager.get(handle)); | |||
EXPECT_FALSE(manager.set(fromString<utl::Handle>("00-00-0002-00000000"), 553)); | |||
EXPECT_EQ (554, manager.get(handle)); | |||
} |
@@ -488,11 +488,11 @@ TEST(LinqTest, to_lookup) | |||
ASSERT_EQ (std::string("Str2-1"), range2.front()); | |||
ASSERT_FALSE(range2.next()); | |||
using lookup_type = decltype(lookup); | |||
using key_value_range_type = linq::lookup_key_value_range_type<int&, std::string&>; | |||
auto map = lookup | |||
>> to_map([](lookup_type::range_type::value_type v){ | |||
>> to_map([](key_value_range_type::value_type v){ | |||
return v.first; | |||
}, [](lookup_type::range_type::value_type v){ | |||
}, [](key_value_range_type::value_type v){ | |||
return v.second >> to_vector(); | |||
}); | |||
@@ -505,6 +505,79 @@ TEST(LinqTest, to_lookup) | |||
EXPECT_EQ(expected, map); | |||
} | |||
struct StationMock | |||
{ | |||
uint32_t id; | |||
std::string name1; | |||
std::string name2; | |||
std::string name3; | |||
std::string name4; | |||
}; | |||
struct op_select_names | |||
{ | |||
using pair_type = std::pair<std::string, uint32_t>; | |||
using vector_type = std::vector<pair_type>; | |||
inline void addToVec(vector_type& vec, const std::string& name, uint32_t sID) | |||
{ | |||
if (name.empty()) | |||
return; | |||
bool exists = from_container(vec) | |||
>> select(op_select_key_default()) | |||
>> contains(name); | |||
if (!exists) | |||
vec.emplace_back(name, sID); | |||
} | |||
inline vector_type operator()(StationMock& s) | |||
{ | |||
vector_type ret; | |||
addToVec(ret, s.name1, s.id); | |||
addToVec(ret, s.name2, s.id); | |||
addToVec(ret, s.name3, s.id); | |||
addToVec(ret, s.name4, s.id); | |||
return ret; | |||
} | |||
}; | |||
void checkMapEntry(std::map<std::string, std::vector<uint32_t>>& map, std::string name, std::vector<uint32_t> ids) | |||
{ | |||
auto it = map.find(name); | |||
ASSERT_NE(it, map.end()); | |||
EXPECT_EQ(name, it->first); | |||
EXPECT_EQ(ids, it->second); | |||
} | |||
TEST(LinqTest, to_lookup_2) | |||
{ | |||
std::vector<StationMock> stations ({ | |||
{ 1, "sname11" , "sname12", "sname13", "sname14" }, | |||
{ 2, "sname21" , "sname21", "sname23", "sname24" }, | |||
{ 3, "sname11" , "sname31", "sname33", "sname34" }, | |||
}); | |||
using key_value_range_type = linq::lookup_key_value_range_type<std::string, uint32_t>; | |||
auto myMap = linq::from_container(stations) | |||
>> linq::select_many(op_select_names()) | |||
>> linq::to_lookup() | |||
>> linq::to_map([](key_value_range_type::value_type p) { | |||
return p.first; | |||
}, [](key_value_range_type::value_type p) { | |||
return p.second >> linq::to_vector(); | |||
}); | |||
checkMapEntry(myMap, "sname11", { 1, 3 }); | |||
checkMapEntry(myMap, "sname12", { 1 }); | |||
checkMapEntry(myMap, "sname13", { 1 }); | |||
checkMapEntry(myMap, "sname14", { 1 }); | |||
checkMapEntry(myMap, "sname21", { 2 }); | |||
checkMapEntry(myMap, "sname23", { 2 }); | |||
checkMapEntry(myMap, "sname24", { 2 }); | |||
checkMapEntry(myMap, "sname31", { 3 }); | |||
checkMapEntry(myMap, "sname33", { 3 }); | |||
checkMapEntry(myMap, "sname34", { 3 }); | |||
} | |||
TEST(LinqTest, moveable_objects) | |||
{ | |||
std::vector<MoveOnlyData> data; | |||