. 줄 정보

다음 구조 조정 대상은 정렬의 핵심인 GetLine 함수이다. 이 함수는 줄의 시작과 끝을 조사하는 임무를 띠고 있는데, 문자의 폭을 합산하는 시간이 오래 걸리는데다 버퍼의 처음부터 정렬해 와야 하기 때문에 속도가 무척이나 느리다. 게다가 문서가 길어지면 정렬 시간은 길이의 누적분에 비례해서 느려지는 치명적인 문제점을 가지고 있어 프로그램의 속도 저하에 결정적인 역할을 하고 있다.

줄의 시작과 끝은 이동, 캐럿 처리, 출력, 스크롤 등 거의 모든 곳에서 사용되는 필수정보이며 곳곳에서 GetLine 함수를 반복적으로 호출한다. 아래로 이동하는 VK_DOWN의 코드를 한 번 보아라. GetRCFromOff를 호출하면 이 함수가 GetLine을 호출한다. GetRowCount GetLine을 호출함으로써 마지막 줄의 번호를 구하고 GetXPosOnLine도 간접적으로 GetLine을 호출한다. 한 칸 아래로 내려가는데 정렬을 몇 번씩이나 중복해서 하고 있는 것이다.

GetLine은 버퍼 처음부터 원하는 줄을 찾을 때까지 연산을 반복하기 때문에 줄번호가 크면 클수록 느려진다. 또한 이 함수는 단독으로 동작하는 것이 아니라 한 번 호출할 때마다 GetLineSub를 수십 번 호출한다. 가장 끔직한 함수는 GetRowCount 함수인데 이 함수는 마지막 줄을 찾기 위해 문서 전체를 스캔하고 있다. 실제로 테스트해보면 문서 아래쯤에서 한 칸 밑으로 내려갈 때 GetLineSub는 무려 29000번 호출되고 문서 길이가 늘어나면 호출수는 기하급수적으로 늘어난다.

이런 식이니 아무리 컴퓨터가 빨라도 프로그램이 느려질 수밖에 없으며 줄의 정보를 구하는 다른 방법을 모색하지 않을 수가 없다. 앞 실습에서 문자의 폭을 미리 구해 배열에 저장했듯이 여기서도 유사한 방법을 사용할 것이다. 그러나 문자폭은 실행중에 변하지 않는 상수이지만 줄 정보는 문서가 변할 때마다 재정렬해야 하므로 한 번 조사한 정보를 계속 사용할 수 없고 편집될 때마다 정렬을 다시 해야 한다. 그래도 문서가 변경되지 않으면 반복적으로 재조사를 하지는 않으므로 엄청난 속도 향상을 기대할 수 있다.

줄 정보는 줄의 시작과 끝으로 구성되며 문서에 존재하는 모든 줄에 대해서 정보를 가지고 있어야 하므로 구조체 배열이 되어야 한다. 줄 정보를 저장하기 위한 구조체를 다음과 같이 정의하였다.

 

struct tagLine

{

     int Start;

     int End;

};

 

Start는 줄의 처음, End는 줄을 끝 오프셋을 가진다. 이 구조체형의 포인터 변수를 선언하고 총 줄 수를 저장할 변수도 같이 선언하였다.

 

tagLine *pLine;

int TotalLine;

 

pLine OnCreate에서 동적으로 메모리를 할당받으며 OnDestroy에서 해제된다. 문서의 줄 수는 가변적이지만 일단 10000줄을 상한선으로 잡도록 하자.

 

BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)

{

    int i;

     ....

    pLine=(tagLine *)malloc(sizeof(tagLine)*10000);

    for (i=0;i<10000;i++) {

        pLine[i].Start=-1;

    }

     UpdateScrollInfo();

     ....

 

void OnDestroy(HWND hWnd)

{

     PostQuitMessage(0);

     free(buf);

     free(arHanWidth);

    free(pLine);

}

 

pLine Start 멤버는 -1로 초기화하는데 -1은 문서의 끝이라는 뜻이다. pLine 배열에 줄의 시작과 끝 정보를 한 번만 조사해놓고 이후부터는 GetLine 호출 대신 이 정보를 사용하도록 할 것이다.