본문 바로가기

CS/프밍 잡지식

[직렬화 버퍼] string 다루기

직렬화 버퍼에서 가장 많이 사용하는 데이터 유형 중 하나가 문자열입니다.

오늘은 string을 <<, >>를 오버로딩을 통해 사용하는 방법에 대해 알아보겠습니다. 

 

기본적으로 직렬화 버퍼의 <<, >>를 오버로딩 할 때 가장 중요한 점은, 짝을 맞추는 것이라고 생각합니다.

넣는 방법과 동일하게 빼야 합니다.


string에서 필요한 정보는 기본적으로 문자열 데이터 그 자체와, 그 문자열의 크기입니다.

크기를 알아야 이어지는 문자열을 직렬화 버퍼에서 정확하게 빼올 수 있습니다.


string과 wstring

string은 한글자를 1byte wstring은 wide_char를 사용하기 때문에 글자당 2byte를 먹습니다.

https://basaeng.tistory.com/31

 

[뇌를 자극하는 윈도우즈 시스템 프로그래밍] 2장. 아스키코드 vs 유니코드

https://basaeng.tistory.com/3 컴퓨터로 문자를 표현하는 법개요컴퓨터는 언제나 0과 1만 인식할 수 있다. 모든 문자는 이진수로 변환되어 저장되고 이진수가 다시 문자로 변환되어 우리에게 보이게 된

basaeng.tistory.com

 


operator<<

string에서 직렬화 버퍼로 데이터를 옮기는 operator입니다.

꺼낼 때 length, data순서로 꺼내야하기 때문에 넣을 때도 동일한 순서인 length, data로 넣어야합니다.

 

건실하게 read pointer, write pointer, data size 등 필요한 요소들을 변경해주면 됩니다.

MessageStream& MessageStream::operator<<(const std::string& value)
{
    const int length = static_cast<int>(value.size());
    if (writePos_ + static_cast<int>(sizeof(length)) + length > bufferSize_)
    {
        throw std::out_of_range("Buffer overflow in operator<<");
    }

    std::memcpy(buffer_.data() + writePos_, &length, sizeof(length));
    writePos_ += static_cast<int>(sizeof(length));
    std::memcpy(buffer_.data() + writePos_, value.data(), length);
    writePos_ += length;
    dataSize_ += static_cast<int>(sizeof(length)) + length;
    return *this;
}

 

MessageStream& MessageStream::operator<<(const std::wstring& value)
{
    const int length = static_cast<int>(value.size());
    const int bytes = length * static_cast<int>(sizeof(wchar_t));
    if (writePos_ + static_cast<int>(sizeof(length)) + bytes > bufferSize_)
    {
        throw std::out_of_range("Buffer overflow in operator<<");
    }

    std::memcpy(buffer_.data() + writePos_, &length, sizeof(length));
    writePos_ += static_cast<int>(sizeof(length));
    std::memcpy(buffer_.data() + writePos_, value.data(), bytes);
    writePos_ += bytes;
    dataSize_ += static_cast<int>(sizeof(length)) + bytes;
    return *this;
}

operator>> 

 직렬화 버퍼에서 string으로 데이터를 꺼내는 operator입니다.

꺼낼 때 length, data순서로 꺼냅니다.

 

string자체의 세팅은 단순히 대입만으로 되지 않기 때문에 string의 assign을 사용할 것입니다.

 

MessageStream& MessageStream::operator>>(std::string& value)
{
    int length = 0;
    if (readPos_ + static_cast<int>(sizeof(length)) > writePos_)
    {
        throw std::out_of_range("Buffer underflow in operator>>");
    }

    std::memcpy(&length, buffer_.data() + readPos_, sizeof(length));
    readPos_ += static_cast<int>(sizeof(length));

    if (readPos_ + length > writePos_)
    {
        throw std::out_of_range("Buffer underflow in operator>>");
    }

    value.assign(buffer_.data() + readPos_, length);
    readPos_ += length;
    dataSize_ -= static_cast<int>(sizeof(length)) + length;
    return *this;
}

MessageStream& MessageStream::operator>>(std::wstring& value)
{
    int length = 0;
    if (readPos_ + static_cast<int>(sizeof(length)) > writePos_)
    {
        throw std::out_of_range("Buffer underflow in operator>>");
    }

    std::memcpy(&length, buffer_.data() + readPos_, sizeof(length));
    readPos_ += static_cast<int>(sizeof(length));

    const int bytes = length * static_cast<int>(sizeof(wchar_t));
    if (readPos_ + bytes > writePos_)
    {
        throw std::out_of_range("Buffer underflow in operator>>");
    }

    value.assign(reinterpret_cast<const wchar_t*>(buffer_.data() + readPos_), length);
    readPos_ += bytes;
    dataSize_ -= static_cast<int>(sizeof(length)) + bytes;
    return *this;
}