STL 자료구조 구현 (6) - 이터레이터 구조 변경
기존에는 이터레이터가 벡터에 중첩클래스로 종속되어 있었고 이를 이용하는 형식이었는데, STL의 구조를 면밀히 살펴보니 Iterator은 완전히 별개의 클래스고 자료구조는 여기에 데이터를 담아 반환해줄 뿐인 것 같았다.
그래서 이터레이터를 아예 별개의 클래스로 분리해주었다.
이터레이터의 종류는 InputIterator, OutputIterator, forwardIterator, BiDirectionalIterator, RandomAccessIterator로 총 5가지가 있다고 하는데, 난 일단 벡터에서 사용할 RandomAccessIterator만 구현하였다.
template <typename DataType>
class RandomAccessIterator
{
public:
RandomAccessIterator()
{
}
RandomAccessIterator(const DataType* _DataPtr)
{
DataPtr = const_cast<DataType*>(_DataPtr);
}
RandomAccessIterator(const RandomAccessIterator& _Other)
{
DataPtr = _Other.DataPtr;
}
RandomAccessIterator& operator=(const RandomAccessIterator& _Other)
{
DataPtr = _Other.DataPtr;
return *this;
}
RandomAccessIterator& operator=(RandomAccessIterator&& _Other) noexcept
{
DataPtr = _Other.DataPtr;
_Other.DataPtr = nullptr;
return *this;
}
bool operator==(const RandomAccessIterator& _Other)
{
return (DataPtr == _Other.DataPtr);
}
bool operator!=(const RandomAccessIterator& _Other)
{
return !(*this == _Other);
}
RandomAccessIterator& operator++()
{
(DataPtr)++;
return *this;
}
RandomAccessIterator operator++(int)
{
RandomAccessIterator ReturnIter(*this);
++(*this);
return ReturnIter;
}
RandomAccessIterator& operator--()
{
(DataPtr)--;
return *this;
}
RandomAccessIterator operator--(int)
{
RandomAccessIterator ReturnIter(*this);
--(*this);
return ReturnIter;
}
RandomAccessIterator& operator+(int _Offset)
{
DataPtr += _Offset;
return *this;
}
RandomAccessIterator& operator-(int _Offset)
{
DataPtr -= _Offset;
return *this;
}
DataType& operator*()
{
return *(DataPtr);
}
void Debug()
{
std::cout << *(DataPtr);
}
private:
DataType* DataPtr = nullptr;
};
bool을 제외한 자료형에 대해서 위와 같이 선언해주었다. 기존의 이터레이터와 정의는 완전히 동일하다.
따로 수정을 안해도 될 것 같아서 그대로 외부로 꺼내기만 했는데, 이는 추후 테스트를 좀 해봐야 할 듯 하다.
bool타입이 문제가 좀 많았다. 먼저, *연산자를 사용하면 bool값을 반환해야 하는 동시에 *연산자로 반환된 데이터에 =연산자를 통해 값을 바꿀 수도 있어야 했다. 아무래도 bool 타입은 비트단위로 관리되다 보니 일반적인 포인터로 구현하는 것이 불가능했는데, 이를 중첩클래스를 활용해 해결하였다. 먼저 코드 전문을 보자.
template<>
class RandomAccessIterator<bool>
{
class BitReference;
public:
RandomAccessIterator()
{
}
RandomAccessIterator(unsigned int* _DataPtr, size_t _BitIndex)
{
DataPtr = _DataPtr;
BitIndex = _BitIndex;
}
RandomAccessIterator(const RandomAccessIterator& _Other)
{
DataPtr = _Other.DataPtr;
BitIndex = _Other.BitIndex;
}
RandomAccessIterator& operator=(const RandomAccessIterator& _Other)
{
DataPtr = _Other.DataPtr;
BitIndex = _Other.BitIndex;
return *this;
}
RandomAccessIterator& operator=(RandomAccessIterator&& _Other) noexcept
{
DataPtr = _Other.DataPtr;
BitIndex = _Other.BitIndex;
_Other.DataPtr = nullptr;
return *this;
}
bool operator==(const RandomAccessIterator& _Other)
{
return (DataPtr == _Other.DataPtr && BitIndex == _Other.BitIndex);
}
bool operator!=(const RandomAccessIterator& _Other)
{
return !(*this == _Other);
}
RandomAccessIterator& operator++()
{
BitIndex++;
if (BitIndex >= 32)
{
BitIndex = 0;
DataPtr++;
}
return *this;
}
RandomAccessIterator operator++(int)
{
RandomAccessIterator ReturnIter(*this);
++(*this);
return ReturnIter;
}
RandomAccessIterator& operator--()
{
BitIndex--;
if (BitIndex < 0)
{
BitIndex = 31;
DataPtr--;
}
return *this;
}
RandomAccessIterator operator--(int)
{
RandomAccessIterator ReturnIter(*this);
--(*this);
return ReturnIter;
}
RandomAccessIterator operator+(int _Offset)
{
size_t ReturnBitIndex = BitIndex + _Offset;
unsigned int* ReturnDataPtr = DataPtr;
while (ReturnBitIndex >= 32)
{
ReturnBitIndex -= 32;
ReturnDataPtr++;
}
return RandomAccessIterator(ReturnDataPtr, ReturnBitIndex);
}
RandomAccessIterator operator-(int _Offset)
{
size_t ReturnBitIndex = BitIndex - _Offset;
unsigned int* ReturnDataPtr = DataPtr;
while (ReturnBitIndex >= 32)
{
ReturnBitIndex += 32;
ReturnDataPtr--;
}
return RandomAccessIterator(ReturnDataPtr, ReturnBitIndex);
}
BitReference operator*()
{
return BitReference(DataPtr, BitIndex);
}
void Debug()
{
std::cout << *(DataPtr);
}
private:
class BitReference
{
public:
BitReference(const unsigned int* _DataPtr, size_t _BitIndex)
{
DataPtr = const_cast<unsigned int*>(_DataPtr);
BitIndex = _BitIndex;
}
operator bool() const
{
return (*DataPtr) & (1 << BitIndex);
}
void operator=(bool _Value)
{
if (_Value == true)
{
(*DataPtr) |= (1 << BitIndex);
}
else
{
(*DataPtr) &= ~(1 << BitIndex);
}
}
private:
unsigned int* DataPtr = nullptr;
size_t BitIndex = 0;
};
private:
unsigned int* DataPtr = nullptr;
size_t BitIndex = 0;
};
먼저, *연산자를 호출하면 BitReference라는 클래스를 생성하여 이를 반환하도록 하였다. 그리고 BitReference 클래스 내부에 = 연산자를 오버로딩하여 이를 통해 값을 바꿀 수 있도록 하였다.
또한, *연산자를 통해 bool 값도 반환받을 수 있어야 하기 때문에 BitReference 클래스에 bool타입으로의 캐스팅 연산자를 오버로딩하여 값을 받을 수 있도록 하였다.