Added Meta/Matching, progress on Bitset/Manager
This commit is contained in:
parent
bee0c9d26d
commit
f123f075eb
7 changed files with 382 additions and 27 deletions
|
@ -2,12 +2,15 @@ cmake_minimum_required(VERSION 3.0)
|
||||||
project(EntityComponentSystem)
|
project(EntityComponentSystem)
|
||||||
|
|
||||||
set(EntityComponentSystem_HEADERS
|
set(EntityComponentSystem_HEADERS
|
||||||
EC/Meta/TypeList.hpp
|
|
||||||
EC/Meta/Combine.hpp
|
EC/Meta/Combine.hpp
|
||||||
EC/Meta/Contains.hpp
|
EC/Meta/Contains.hpp
|
||||||
EC/Meta/ContainsAll.hpp
|
EC/Meta/ContainsAll.hpp
|
||||||
|
EC/Meta/ForEach.hpp
|
||||||
EC/Meta/IndexOf.hpp
|
EC/Meta/IndexOf.hpp
|
||||||
|
EC/Meta/Matching.hpp
|
||||||
EC/Meta/Morph.hpp
|
EC/Meta/Morph.hpp
|
||||||
|
EC/Meta/TypeList.hpp
|
||||||
|
EC/Meta/TypeListGet.hpp
|
||||||
EC/Meta/Meta.hpp
|
EC/Meta/Meta.hpp
|
||||||
EC/Bitset.hpp
|
EC/Bitset.hpp
|
||||||
EC/Manager.hpp
|
EC/Manager.hpp
|
||||||
|
@ -53,6 +56,7 @@ find_package(GTest)
|
||||||
if(GTEST_FOUND)
|
if(GTEST_FOUND)
|
||||||
set(UnitTests_SOURCES
|
set(UnitTests_SOURCES
|
||||||
test/MetaTest.cpp
|
test/MetaTest.cpp
|
||||||
|
test/ECTest.cpp
|
||||||
test/Main.cpp)
|
test/Main.cpp)
|
||||||
|
|
||||||
add_executable(UnitTests ${UnitTests_SOURCES})
|
add_executable(UnitTests ${UnitTests_SOURCES})
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Meta/TypeList.hpp"
|
#include "Meta/TypeList.hpp"
|
||||||
#include "Meta/Combine.hpp"
|
#include "Meta/Combine.hpp"
|
||||||
#include "Meta/IndexOf.hpp"
|
#include "Meta/IndexOf.hpp"
|
||||||
|
#include "Meta/ForEach.hpp"
|
||||||
|
|
||||||
namespace EC
|
namespace EC
|
||||||
{
|
{
|
||||||
|
@ -30,17 +31,14 @@ namespace EC
|
||||||
template <typename Contents>
|
template <typename Contents>
|
||||||
static constexpr Bitset<ComponentsList, TagsList> generateBitset()
|
static constexpr Bitset<ComponentsList, TagsList> generateBitset()
|
||||||
{
|
{
|
||||||
//TODO
|
|
||||||
Bitset<ComponentsList, TagsList> bitset;
|
Bitset<ComponentsList, TagsList> bitset;
|
||||||
/*
|
|
||||||
for(unsigned int i = 0; i < Contents::size; ++i)
|
EC::Meta::forEach<Contents>([&bitset] (auto t) {
|
||||||
|
if(EC::Meta::Contains<decltype(t), Combined>::value)
|
||||||
{
|
{
|
||||||
if(EC::Meta::Contains<EC::Meta::TypeListGet<Contents, i>, Combined>::value)
|
bitset[EC::Meta::IndexOf<decltype(t), Combined>::value] = true;
|
||||||
{
|
|
||||||
bitset[EC::Meta::IndexOf<EC::Meta::TypeListGet<Contents, i>, Combined>::value] = true;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
return bitset;
|
return bitset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
#ifndef EC_MANAGER_HPP
|
#ifndef EC_MANAGER_HPP
|
||||||
#define EC_MANAGER_HPP
|
#define EC_MANAGER_HPP
|
||||||
|
|
||||||
#define EC_INIT_ENTITIES_SIZE 1024
|
#define EC_INIT_ENTITIES_SIZE 256
|
||||||
|
#define EC_GROW_SIZE_AMOUNT 256
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "Meta/Combine.hpp"
|
#include "Meta/Combine.hpp"
|
||||||
#include "Bitset.hpp"
|
#include "Bitset.hpp"
|
||||||
|
@ -19,29 +21,189 @@ namespace EC
|
||||||
using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
|
using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
|
||||||
using BitsetType = EC::Bitset<ComponentsList, TagsList>;
|
using BitsetType = EC::Bitset<ComponentsList, TagsList>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename... Types>
|
||||||
|
struct Storage
|
||||||
|
{
|
||||||
|
using type = std::tuple<std::vector<Types>... >;
|
||||||
|
};
|
||||||
|
using ComponentsStorage = typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
||||||
|
// Entity: isAlive, dataIndex, ComponentsTags Info
|
||||||
|
using EntitiesTupleType = std::tuple<bool, std::size_t, BitsetType>;
|
||||||
|
using EntitiesType = std::vector<EntitiesTupleType>;
|
||||||
|
|
||||||
|
EntitiesType entities;
|
||||||
|
ComponentsStorage componentsStorage;
|
||||||
|
std::size_t currentCapacity = 0;
|
||||||
|
std::size_t currentSize = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
Manager()
|
Manager()
|
||||||
{
|
{
|
||||||
entities.resize(EC_INIT_ENTITIES_SIZE);
|
resize(EC_INIT_ENTITIES_SIZE);
|
||||||
|
|
||||||
for(auto entity : entities)
|
|
||||||
{
|
|
||||||
entity->first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename EComponentsList>
|
|
||||||
std::size_t addEntity()
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
BitsetType newEntity;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using ComponentsStorage = EC::Meta::Morph<ComponentsList, std::tuple<> >;
|
void resize(std::size_t newCapacity)
|
||||||
using EntitiesType = std::tuple<bool, BitsetType>;
|
{
|
||||||
|
if(currentCapacity >= newCapacity)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<EntitiesType> entities;
|
EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
|
||||||
|
std::get<std::vector<decltype(t)> >(this->componentsStorage).resize(newCapacity);
|
||||||
|
});
|
||||||
|
|
||||||
|
entities.resize(newCapacity);
|
||||||
|
for(std::size_t i = currentCapacity; i < newCapacity; ++i)
|
||||||
|
{
|
||||||
|
entities[i] = std::make_tuple(false, i, BitsetType{});
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCapacity = newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::size_t addEntity()
|
||||||
|
{
|
||||||
|
if(currentSize == currentCapacity)
|
||||||
|
{
|
||||||
|
resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::get<bool>(entities[currentSize]) = true;
|
||||||
|
|
||||||
|
return currentSize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteEntity(std::size_t index)
|
||||||
|
{
|
||||||
|
std::get<bool>(entities.at(index)) = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasEntity(std::size_t index) const
|
||||||
|
{
|
||||||
|
return index < currentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EntitiesTupleType& getEntityInfo(std::size_t index) const
|
||||||
|
{
|
||||||
|
return entities.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
Component& getEntityData(std::size_t index)
|
||||||
|
{
|
||||||
|
return std::get<std::vector<Component> >(componentsStorage).at(std::get<std::size_t>(entities.at(index)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
std::size_t rhs = currentSize - 1;
|
||||||
|
std::size_t lhs = 0;
|
||||||
|
|
||||||
|
while(lhs < rhs)
|
||||||
|
{
|
||||||
|
if(!std::get<bool>(entities[lhs]))
|
||||||
|
{
|
||||||
|
// lhs is marked for deletion
|
||||||
|
// swap lhs entity with rhs entity
|
||||||
|
std::swap(entities[lhs], entities[rhs]);
|
||||||
|
|
||||||
|
// inc/dec pointers
|
||||||
|
++lhs; --rhs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++lhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentSize = rhs + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component, typename... Args>
|
||||||
|
void addComponent(std::size_t entityID, Args&&... args)
|
||||||
|
{
|
||||||
|
if(!hasEntity(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component component(args...);
|
||||||
|
|
||||||
|
std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = true;
|
||||||
|
std::get<std::vector<Component> >(componentsStorage)[std::get<std::size_t>(entities[entityID])] = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Component>
|
||||||
|
void removeComponent(std::size_t entityID)
|
||||||
|
{
|
||||||
|
if(!hasEntity(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
void addTag(std::size_t entityID)
|
||||||
|
{
|
||||||
|
if(!hasEntity(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Tag>
|
||||||
|
void removeTag(std::size_t entityID)
|
||||||
|
{
|
||||||
|
if(!hasEntity(entityID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename... Types>
|
||||||
|
struct ForMatchingSignatureHelper
|
||||||
|
{
|
||||||
|
template <typename CType, typename Function>
|
||||||
|
static void call(std::size_t entityID, CType& ctype, Function&& function)
|
||||||
|
{
|
||||||
|
function(
|
||||||
|
entityID,
|
||||||
|
ctype.template getEntityData<Types>(entityID)...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename Signature, typename Function>
|
||||||
|
void forMatchingSignature(Function&& function)
|
||||||
|
{
|
||||||
|
using SignatureComponents = typename EC::Meta::Matching<Signature, ComponentsList>::type;
|
||||||
|
using Helper = EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
|
||||||
|
|
||||||
|
BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
|
||||||
|
for(std::size_t i = 0; i < currentSize; ++i)
|
||||||
|
{
|
||||||
|
if(!std::get<bool>(entities[i]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset)
|
||||||
|
{
|
||||||
|
Helper::call(i, *this, std::forward<Function>(function));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
54
src/EC/Meta/Matching.hpp
Normal file
54
src/EC/Meta/Matching.hpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
#ifndef EC_META_MATCHING_HPP
|
||||||
|
#define EC_META_MATCHING_HPP
|
||||||
|
|
||||||
|
#include "TypeList.hpp"
|
||||||
|
#include "Contains.hpp"
|
||||||
|
|
||||||
|
namespace EC
|
||||||
|
{
|
||||||
|
namespace Meta
|
||||||
|
{
|
||||||
|
template <typename TTypeListA, typename TTypeListB>
|
||||||
|
struct MatchingHelper
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TTypeListA, typename TTypeListB, typename... Matching>
|
||||||
|
struct MatchingHelperHelper
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TTypeListA, typename TTypeListB, typename... Matching>
|
||||||
|
struct MatchingHelperHelper<TTypeListA, TTypeListB, TypeList<Matching...> >
|
||||||
|
{
|
||||||
|
using type = TypeList<Matching...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class TTypeListA, typename TTypeListB, typename Type, typename... Types, typename... Matching>
|
||||||
|
struct MatchingHelperHelper<TTypeListA<Type, Types...>, TTypeListB, TypeList<Matching...> > :
|
||||||
|
std::conditional<
|
||||||
|
Contains<Type, TTypeListB>::value,
|
||||||
|
MatchingHelperHelper<TTypeListA<Types...>, TTypeListB, TypeList<Matching..., Type> >,
|
||||||
|
MatchingHelperHelper<TTypeListA<Types...>, TTypeListB, TypeList<Matching...> >
|
||||||
|
>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template <typename...> class TTypeListA, typename TTypeListB, typename Type, typename... Types>
|
||||||
|
struct MatchingHelper<TTypeListA<Type, Types...>, TTypeListB> :
|
||||||
|
std::conditional<
|
||||||
|
Contains<Type, TTypeListB>::value,
|
||||||
|
MatchingHelperHelper<TTypeListA<Types...>, TTypeListB, TypeList<Type> >,
|
||||||
|
MatchingHelper<TTypeListA<Types...>, TTypeListB>
|
||||||
|
>::type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TTypeListA, typename TTypeListB>
|
||||||
|
using Matching = MatchingHelper<TTypeListA, TTypeListB>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -7,4 +7,5 @@
|
||||||
#include "IndexOf.hpp"
|
#include "IndexOf.hpp"
|
||||||
#include "Morph.hpp"
|
#include "Morph.hpp"
|
||||||
#include "ForEach.hpp"
|
#include "ForEach.hpp"
|
||||||
|
#include "Matching.hpp"
|
||||||
|
|
||||||
|
|
106
src/test/ECTest.cpp
Normal file
106
src/test/ECTest.cpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <EC/Meta/Meta.hpp>
|
||||||
|
#include <EC/EC.hpp>
|
||||||
|
|
||||||
|
struct C0 {
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
struct C1 {
|
||||||
|
int vx, vy;
|
||||||
|
};
|
||||||
|
struct C2 {};
|
||||||
|
struct C3 {};
|
||||||
|
|
||||||
|
struct T0 {};
|
||||||
|
struct T1 {};
|
||||||
|
|
||||||
|
using ListComponentsAll = EC::Meta::TypeList<C0, C1, C2, C3>;
|
||||||
|
using ListComponentsSome = EC::Meta::TypeList<C1, C3>;
|
||||||
|
|
||||||
|
using ListTagsAll = EC::Meta::TypeList<T0, T1>;
|
||||||
|
|
||||||
|
using ListAll = EC::Meta::TypeList<C0, C1, C2, C3, T0, T1>;
|
||||||
|
|
||||||
|
using EmptyList = EC::Meta::TypeList<>;
|
||||||
|
|
||||||
|
using MixedList = EC::Meta::TypeList<C2, T1>;
|
||||||
|
|
||||||
|
TEST(EC, Bitset)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
EC::Bitset<ListComponentsAll, EmptyList> bitset;
|
||||||
|
bitset[1] = true;
|
||||||
|
bitset[3] = true;
|
||||||
|
|
||||||
|
auto genBitset = EC::Bitset<ListComponentsAll, EmptyList>::generateBitset<ListComponentsSome>();
|
||||||
|
|
||||||
|
EXPECT_EQ(bitset, genBitset);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
EC::Bitset<ListAll, EmptyList> bitset;
|
||||||
|
bitset[2] = true;
|
||||||
|
bitset[5] = true;
|
||||||
|
|
||||||
|
auto genBitset = EC::Bitset<ListAll, EmptyList>::generateBitset<MixedList>();
|
||||||
|
|
||||||
|
EXPECT_EQ(bitset, genBitset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EC, Manager)
|
||||||
|
{
|
||||||
|
EC::Manager<ListComponentsAll, ListTagsAll> manager;
|
||||||
|
|
||||||
|
std::size_t e0 = manager.addEntity();
|
||||||
|
std::size_t e1 = manager.addEntity();
|
||||||
|
|
||||||
|
manager.addComponent<C0>(e0);
|
||||||
|
manager.addComponent<C1>(e0);
|
||||||
|
|
||||||
|
manager.addComponent<C0>(e1);
|
||||||
|
manager.addComponent<C1>(e1);
|
||||||
|
manager.addTag<T0>(e1);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& pos = manager.getEntityData<C0>(e0);
|
||||||
|
pos.x = 5;
|
||||||
|
pos.y = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& vel = manager.getEntityData<C1>(e0);
|
||||||
|
vel.vx = 1;
|
||||||
|
vel.vy = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto posUpdate = [] (std::size_t id, C0& pos, C1& vel) {
|
||||||
|
pos.x += vel.vx;
|
||||||
|
pos.y += vel.vy;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto updateTag = [] (std::size_t id, C0& pos, C1& vel) {
|
||||||
|
pos.x = pos.y = vel.vx = vel.vy = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
manager.forMatchingSignature<EC::Meta::TypeList<C0, C1> >(posUpdate);
|
||||||
|
manager.forMatchingSignature<EC::Meta::TypeList<C0, C1> >(posUpdate);
|
||||||
|
|
||||||
|
manager.forMatchingSignature<EC::Meta::TypeList<C0, C1, T0> >(updateTag);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& pos = manager.getEntityData<C0>(e0);
|
||||||
|
EXPECT_EQ(pos.x, 7);
|
||||||
|
EXPECT_EQ(pos.y, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.deleteEntity(e0);
|
||||||
|
manager.cleanup();
|
||||||
|
|
||||||
|
std::size_t edata = std::get<std::size_t>(manager.getEntityInfo(0));
|
||||||
|
EXPECT_EQ(edata, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,14 @@ using ListTagsAll = EC::Meta::TypeList<T0, T1>;
|
||||||
|
|
||||||
using ListAll = EC::Meta::TypeList<C0, C1, C2, C3, T0, T1>;
|
using ListAll = EC::Meta::TypeList<C0, C1, C2, C3, T0, T1>;
|
||||||
|
|
||||||
|
using ListSome = EC::Meta::TypeList<C1, C3, T1>;
|
||||||
|
|
||||||
|
template <typename... STypes>
|
||||||
|
struct Storage
|
||||||
|
{
|
||||||
|
using type = std::tuple<std::vector<STypes>... >;
|
||||||
|
};
|
||||||
|
|
||||||
TEST(Meta, Contains)
|
TEST(Meta, Contains)
|
||||||
{
|
{
|
||||||
int size = ListComponentsAll::size;
|
int size = ListComponentsAll::size;
|
||||||
|
@ -157,6 +165,13 @@ TEST(Meta, Morph)
|
||||||
using MorphedComponents = EC::Meta::Morph<ListComponentsAll, std::tuple<> >;
|
using MorphedComponents = EC::Meta::Morph<ListComponentsAll, std::tuple<> >;
|
||||||
bool isSame = std::is_same<MorphedComponents, TupleAll>::value;
|
bool isSame = std::is_same<MorphedComponents, TupleAll>::value;
|
||||||
EXPECT_TRUE(isSame);
|
EXPECT_TRUE(isSame);
|
||||||
|
|
||||||
|
|
||||||
|
using ComponentsStorage = EC::Meta::Morph<ListComponentsAll, Storage<> >;
|
||||||
|
|
||||||
|
isSame = std::is_same<ComponentsStorage::type,
|
||||||
|
std::tuple<std::vector<C0>, std::vector<C1>, std::vector<C2>, std::vector<C3> > >::value;
|
||||||
|
EXPECT_TRUE(isSame);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Meta, TypeListGet)
|
TEST(Meta, TypeListGet)
|
||||||
|
@ -199,3 +214,18 @@ TEST(Meta, ForEach)
|
||||||
EXPECT_FALSE(bitset[5]);
|
EXPECT_FALSE(bitset[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Meta, Matching)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
using Matched = EC::Meta::Matching<ListComponentsSome, ListComponentsAll>::type;
|
||||||
|
bool isSame = std::is_same<ListComponentsSome, Matched>::value;
|
||||||
|
EXPECT_TRUE(isSame);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
using Matched = EC::Meta::Matching<ListSome, ListAll>::type;
|
||||||
|
bool isSame = std::is_same<ListSome, Matched>::value;
|
||||||
|
EXPECT_TRUE(isSame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue