[언리얼 엔진] TMap
- ⭐ Game Programming/Unreal Document
- 2021. 8. 16.
언리얼 엔진 TMap
- 언리얼 엔진(Unreal Engine)에서 TArray 다음으로 많이 사용되는 TMap일 것이다.
- 키와 값을 짝으로 데이터를 저장하는 방식
- 키로 값을 검색하여 값을 얻을수 있다.
만들고 채우기
- Add 함수에 Key와 Value를 입력하여 컨테이너에 데이터를 추가한다.
- 중복된 키를 추가하면 기존의 같은 키에 있는 Value를 대체한다.
- Key만 넣게 되면 Value는 Value타입의 기본 생성자로 생성된다.
TMap<int32, FString> FruitMap;
FruitMap.Add(5, TEXT("Banana"));
FruitMap.Add(2, TEXT("Grapefruit"));
FruitMap.Add(7, TEXT("Pineapple"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Grapefruit" },
// { Key: 7, Value: "Pineapple" }
// ]
FruitMap.Add(2, TEXT("Pear"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" }
// ]
FruitMap.Add(4);
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "" }
// ]
- TArray 처럼 Emplace 함수로 임시생성을 피할 수 있다.
- Append 함수로 다른 TMap의 모든 엘리먼트를 삽입하여 병합할 수 있다.
- Append 함수 사용시 키가 중복되는 값이 있으면 추가되는 값으로 대체된다.
FruitMap.Emplace(3, TEXT("Orange"));
// FruitMap == [
// { Key: 5, Value: "Banana" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "" },
// { Key: 3, Value: "Orange" }
// ]
TMap<int32, FString> FruitMap2;
FruitMap2.Emplace(4, TEXT("Kiwi"));
FruitMap2.Emplace(9, TEXT("Melon"));
FruitMap2.Emplace(5, TEXT("Mango"));
FruitMap.Append(FruitMap2);
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
// 이제 FruitMap2 은 비워져 있다.
반복처리
- TArray와 유사하게 C++의 auto를 이욯나 for 기능 사용 가능
- CreateIterator 를 통해 이터레이터로 반복 처리 가능
for (auto& Elem : FruitMap)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%d, \"%s\")\n"),
Elem.Key,
*Elem.Value
)
);
}
// Output:
// (5, "Mango")
// (2, "Pear")
// (7, "Pineapple")
// (4, "Kiwi")
// (3, "Orange")
// (9, "Melon")
for (auto It = FruitMap.CreateConstIterator(); It; ++It)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%d, \"%s\")\n"),
It.Key(), // same as It->Key
*It.Value() // same as *It->Value
)
);
}
쿼리
- Num 함수를 통해 엘리먼트의 갯수를 알 수 있다.
- Contains 함수로 특정키가 있는지 검색할 수 있다.
- [] 연산자로 해당값을 조회 할 수 있다.
- Find 함수로 엘리먼트의 값의 포인터를 얻어올 수 있다.
- FindorAdd 함수나 FindRef 함수는 결과의 유효성을 보장한다.
(널이 리턴되지 않음)
int32 Count = FruitMap.Num(); // Count == 6
bool bHas7 = FruitMap.Contains(7); // bHas7 == true
bool bHas8 = FruitMap.Contains(8); // bHas8 == false
FString Val7 = FruitMap[7]; // Val7 == "Pineapple"
FString Val8 = FruitMap[8]; // 어서트!
FString* Ptr7 = FruitMap.Find(7); // *Ptr7 == "Pineapple"
FString* Ptr8 = FruitMap.Find(8); // Ptr8 == nullptr
FString& Ref7 = FruitMap.FindOrAdd(7);
// Ref7 == "Pineapple"
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
FString& Ref8 = FruitMap.FindOrAdd(8);
// Ref8 == ""
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" },
// { Key: 8, Value: "" }
// ]
FString Val7 = FruitMap.FindRef(7);
FString Val6 = FruitMap.FindRef(6);
// Val7 == "Pineapple"
// Val6 == ""
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" },
// { Key: 8, Value: "" }
// ]
- FindKey 함수는 값을 검사해서 키를 찾는다.
- 선형 검사를 하기때문에 느리다.
(그래도 필요하면 해야지)
(그런데 필요할 경우가 생긴다면 TMap을 쓰면 안되지..)
const int32* KeyMangoPtr = FruitMap.FindKey(TEXT("Mango"));
const int32* KeyKumquatPtr = FruitMap.FindKey(TEXT("Kumquat"));
// *KeyMangoPtr == 5
// KeyKumquatPtr == nullptr
제거
- Remove 함수는 인자에 키값을 넣으면 해당 키를 가진 엘리먼트가 제거된다.
- Empty와 Reset 함수로 모든 엘리먼트를 삭제할 수 있다.
- Empty는 남겨질 슬랙 양을 지정할 수 있고, Reset은 기존의 슬랙 양을 유지한다.
FruitMap.Remove(8);
// FruitMap == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
TMap<int32, FString> FruitMapCopy = FruitMap;
// FruitMapCopy == [
// { Key: 5, Value: "Mango" },
// { Key: 2, Value: "Pear" },
// { Key: 7, Value: "Pineapple" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" },
// { Key: 9, Value: "Melon" }
// ]
FruitMapCopy.Empty(); // 여기서 Reset() 을 호출해도 된다.
// FruitMapCopy == []
소팅
- KeySort와 ValueSort 함수는 각각 키 / 값으로 지정한 술부를 통해 정렬을 할 수 있다.
FruitMap.KeySort([](int32 A, int32 B) {
return A > B; // sort keys in reverse
});
// FruitMap == [
// { Key: 9, Value: "Melon" },
// { Key: 5, Value: "Mango" },
// { Key: 4, Value: "Kiwi" },
// { Key: 3, Value: "Orange" }
// ]
FruitMap.ValueSort([](const FString& A, const FString& B) {
return A.Len() < B.Len(); // sort strings by length
});
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Mango" },
// { Key: 9, Value: "Melon" },
// { Key: 3, Value: "Orange" }
// ]
연산자
- TMap은 TArray와 같이 복사 생성자나 할당 연산자를 통해서 복사가 가능하다.
- MoveTemp 함수로 이동 시멘틱 지원하여 이동 이후 기존 맵은 빈상태가 된다.
TMap<int32, FString> NewMap = FruitMap;
NewMap[5] = "Apple";
NewMap.Remove(3);
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Mango" },
// { Key: 9, Value: "Melon" },
// { Key: 3, Value: "Orange" }
// ]
// NewMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Apple" },
// { Key: 9, Value: "Melon" }
// ]
FruitMap = MoveTemp(NewMap);
// FruitMap == [
// { Key: 4, Value: "Kiwi" },
// { Key: 5, Value: "Apple" },
// { Key: 9, Value: "Melon" }
// ]
// NewMap == []
슬랙
- Slack (여유분, 슬랙)은 할당된 메모리에 엘리먼트가 없는 것을 말한다.
- Reserve 함수로 엘리먼트 없이 메모리만 할당 할 수 있다.
FruitMap.Reserve(10);
for (int32 i = 0; i < 10; ++i)
{
FruitMap.Add(i, FString::Printf(TEXT("Fruit%d"), i));
}
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// { Key: 8, Value: "Fruit8" },
// ...
// { Key: 1, Value: "Fruit1" },
// { Key: 0, Value: "Fruit0" }
// ]
- Compact 와 Shrink 함수로 슬랙을 제거 할 수 있다.
- Shrink 함수는 컨테이너 중간의 슬랙부분은 제거하지 않고 끝의 모든 슬랙만 제거한다.
- Compact 함수는 빈 슬랙을 컨테이너의 끝으로 모아준다.
for (int32 i = 0; i < 10; i += 2)
{
FruitMap.Remove(i);
}
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// <invalid>,
// { Key: 7, Value: "Fruit7" },
// <invalid>,
// { Key: 5, Value: "Fruit5" },
// <invalid>,
// { Key: 3, Value: "Fruit3" },
// <invalid>,
// { Key: 1, Value: "Fruit1" },
// <invalid>
// ]
FruitMap.Shrink();
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// <invalid>,
// { Key: 7, Value: "Fruit7" },
// <invalid>,
// { Key: 5, Value: "Fruit5" },
// <invalid>,
// { Key: 3, Value: "Fruit3" },
// <invalid>,
// { Key: 1, Value: "Fruit1" }
// ]
FruitMap.Compact();
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// { Key: 7, Value: "Fruit7" },
// { Key: 5, Value: "Fruit5" },
// { Key: 3, Value: "Fruit3" },
// { Key: 1, Value: "Fruit1" },
// <invalid>,
// <invalid>,
// <invalid>,
// <invalid>
// ]
FruitMap.Shrink();
// FruitMap == [
// { Key: 9, Value: "Fruit9" },
// { Key: 7, Value: "Fruit7" },
// { Key: 5, Value: "Fruit5" },
// { Key: 3, Value: "Fruit3" },
// { Key: 1, Value: "Fruit1" }
// ]
반응형