// 언리얼 C++ 기본 타입과 문자열

// 언리얼은 c++ 기본타입을 사용하지않고 자체적으로 만든 통합된 타입을 사용한다.
// why? -> 플랫폼 파편화로 인해 다양한 플랫폼에서 동일하게 동작하기 위함
// 플랫폼 파편화 ? -> 과거부터 현재까지 다양한 기기에서 C++를 지원하는데 여기서 데이터타입에 대한 정보가 각자 명확하지 않아 플랫폼마다 대응이 필요했고 이를 플랫폼 파편화라고 한다.

// -> 데이터 정보가 명확해야 한다.
// -> 게임제작은 단일 하드웨이 기기에서 최대 퍼포먼스를 뽑아내야 하기 때문에
// -> 네트워크 상에서 데이터 정보가 명확해야 효율적이며 안정적임
// -> 그럼에도 int는 많은 플랫폼에서 데이터 정보가 다르기 때문에 int32를 규약하고 있고 언리얼도 이 표준에 맞춰서 사용하기를 권장하고있다.

// TCHAR
// -> 언리얼에서는 별도의 TCHAR 타입의 문자열을 사용하도록 지정하고있다.
// why? -> 문자열의 경우 유니코드 및 ANSI 문자 모두를 지원하기 때문이다. 따라서 'TCHAR' 를 사용하면 다양한 문자 유형과 호환성 문제를 최소화 할 수 있다.

// bool -> uint8
// -> 언리얼에서 클래스 멤버로 boolean 타입을 선언시 bool 타입또한 플랫폼마다 데이터 타입이 애매모호 하기 때문에 uint8:1 형태로 1byte씩 잘라서 사용하기를 권장하고 있다. 이렇게 사용하면 동일하게 1byte의 데이터로 사용

// 언리얼 문자열 처리 방식
// TCHAR <-> FString <-> FCString
// TCHAR에서 FString으로 변환을 할 때 대입을 통해서 쉽게 가능하고, FString은 언리얼에서 제공하는 TArray 형태의 동적배열로 변환하게 된다.
// FString은 Helper Class지만 실제론 문자열에 대한 다양한 처리를 담당하는건 FCString 통해서 하게 된다.

// FString
// 문자열 처리를 할수있는 다양한 API 기능을 제공하는 Helper Class 라고 할 수 있음

// FCString
// c라이브러리 언어의 기능들을 사용하여 문자열을 처리하는 역할을 한다.

// FName
// 경량화된 문자열 자료형
// 언리얼에선 자체적으로 FNamePool 이라는 해시테이블 구조(Key(해쉬값):Value(문자열)) 의 문자열 풀이 사용된다. 이미 풀에 등록된 문자열이 있다면 빠르게 Key값을 검색해 찾을 수 있다.
// 대소문자를 구별하지 않으며 이미 등록된 문자열은 수정이 불가능하다.
// 따라서 프로젝트에 사용될 문자열이 변경이 불필요 할 경우 FName을 통해서 사용할 이유가 된다. 이유는 속도적인 측면에서 이득이 있기 때문에

// Fill out your copyright notice in the Description page of Project Settings.

#include "Components/EditableTextBox.h"
#include "MyGameInstance.h"

UMyGameInstance::UMyGameInstance()
{

}

void UMyGameInstance::Init()
{
    Super::Init();

    static const TCHAR LogCharArray[] = TEXT("Hellow Unreal"); // TCHAR 문자 자료형의 연속공간을 선언. 문자열로 사용할 수 있다. 
    // static const 는 5.2 버전부터 UE_LOG 매크로 인수가 달라져서 임시로 붙임.
    UE_LOG(LogTemp, Log, LogCharArray);

    FString LogCharString = LogCharArray;
    UE_LOG(LogTemp, Log, TEXT("%s"), *LogCharString); // TCHAR 문자열을 가지고있는 문자열 클래스임 클래스 내부에서 제공되는 유용한 기능들이 탑재 되어있다. 

    // TEXT("HELLO") -> TCHAR[5]{'H','E','L','L','O'} <*=> FString <=> FCString

    // FString 문자열을 TCHAR* 문자열로 받고자할 때
    const TCHAR* LongCharPtr = *LogCharString; // * Operator를 보면 const TCHAR* 로만 받을 수 있기때문에 const TCHAR*로 받는다. 변경 불가능
    TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData(); // TArray<*CHAR> 로 변환 뒤 포인터 배열의 시작주소를 넘겨준다.
    
    // TCHAR Array로 받아야한다면
    //TArray<TCHAR> bb(LogCharString.GetCharArray(),LogCharString.GetCharArray().GetSlack());
    
    TCHAR LogCharArrayWithSize[100];
    FCString::Strcpy(LogCharArrayWithSize, LogCharString.Len(), *LogCharString); // 저수준 복사

    // LogCharString 문자열에서 "unreal" 문자열이 포함되는지 확인할 수 있음
    if(LogCharString.Contains(TEXT("unreal"), ESearchCase::IgnoreCase)) // ESearchCase::IgnoreCase = 대소문자 구별 X, ESearchCase::CaseSensitive = 구별 O
    {
         //문자열 인덱스 찾기
         int32 Index = LogCharString.Find(TEXT("unreal"), ESearchCase::IgnoreCase);
         // 자르기
         FString EndString = LogCharString.Mid(Index);
         UE_LOG(LogTemp, Log, TEXT("Find Test %s"), *EndString);
    }

    FString Left, Right;
    if(LogCharString.Split(TEXT(" "), &Left, &Right)) // Hellow Unreal => Left = Hellow, Right = Unreal
    {
        UE_LOG(LogTemp, Log, TEXT("Split Test : %s 와 %s"), *Left, *Right); 
        // Window 환경에서 코드작성시 파일인코딩이 CP949형식의 멀티바이트로 되어있음 이걸 유니코드로 바꿔줘야한다. 
        // 파일 저장시 인코딩 형식을 변경할 때 UTF-8 형태로 저장하면 된다. BOM 은 3바이트 정보가 들어있는 인코딩 형태 Linux는 BOM 지원 X
    }

    int32 IntValue = 32;
    float FloatValue = 3.141592;

    FString FloatString = FString::SanitizeFloat(FloatValue); // float -> FString
    FString IntString = FString::FromInt(IntValue); // int -> FString
    FString FloatIntString = FString::Printf(TEXT("%f%d"),FloatValue, IntValue); // Float + Int -> FString

    UE_LOG(LogTemp, Log, TEXT("FloatString : %s"), *FloatString); 
    UE_LOG(LogTemp, Log, TEXT("IntString : %s"), *IntString); 
    UE_LOG(LogTemp, Log, TEXT("FloatIntString : %s"), *FloatIntString);

    int32 IntValueFromString = FCString::Atoi(*IntString); // ASCII to int          // 안전성 주의
    float FloatValueFromString = FCString::Atof(*FloatString); // ASCII to float    // 안전성 주의

    //FString은 언리얼에서 사용되는 다양한 문자열에 변환 주체가 됨 FString -> FName, FString -> FText

    //FName Class
    //FName은 애셋 관리를 위해 사용되는 문자열 체계임, 대소문자 구분 X, 선언 후 수정 X, 가볍고 빠르다
    //Global FName Pool 자료구조를 가지고있다.
    //FName 문자열을 Instance로 만들면 Global Pool에서 값을 저장한다. 이때 Global Pool 에서 해시 값을 추출하여 Key값으로 사용 결과적으로 Key(해쉬) : Value(FName) 이 된다.
    //가볍고 빠른 이유는 이러한 구조를 가지고있기 때문이다.

    
    for(int i = 0; i < 10000; ++i)
    {
        FName SearchInNamePool = FName(TEXT("pelvis")); 
        // 주의할점은 앞서 FName Global Pool에서 관리 되고있다고 했는데, FName 생성자에 지속적으로 같은 문자열을 넣고 반복작업을 할 때
        // Global Pool에서 문자열을 검사하는 작업을 반복 수행 하기 때문에 많은 오버헤드가 발생 할 수 있다.
        // 따라서 이렇게 계속 생성하는 것 보다 한번만 생성 후 참조해서 쓰는게 좋을것 같다.
    }
}


