SlideShare a Scribd company logo
제 4장
빛의 속도록 

XML 파싱하기
김경렬
XML 파싱 모형.
❖ SAX(Simple API for XML) - 스트림과 ‘태그 시작, 끝, 문
자자료’등의 콜백으로 데이터 처리.!
❖ Pull Parsing - SAX 유사, iterator 객체를 통해 제어.!
❖ DOM(Document Object Model) - 입력을 문서 객체로 변
환후 처리.
pugixml DOM 파서
❖ 메모리 안에 들어갈 정도로 작은 문서.!
❖ 방문할 노드들이 서로 참조하는 복잡한 구조를 가진 문서!
❖ 복잡한 방식으로 변환해야 하는 문서.
pugixml 설계상의 선택
❖ 아주 빠르고 가벼운 DOM 기반 XML 조작 라이브러리를
목표로 개발.!
❖ 성능과 XML 검증의 절충점.!
❖ well-formed 검증.!
❖ DTD(Document Type Declaration)은 검증 않함.!
❖ 종종 well-formed 가 아닌 경우도 성공으로 처리.
파싱
❖ 토큰 스트림 대신 문자 스트림에 대해 파싱을 수행.!
❖ UTF-8 문자만 지원.!
❖ 제자리 파싱(In-place parsing) - 스트림에 있는 자료를 직
접 처리하는 방식.

문자열 복사를 최소화하기 위해.
In-place parsing
❖ 문자열을 만나면 그 문자열의 포인터와 길이를 저장.!
❖ 성능 좋아지지만, 메모리 사용량은 증가.

- 원본 스트림 유지.
< n > T h e n o d e t e x t < / n >
포인터0xabc3, 길이 130xabc0
In-place parsing - 널문자 처리
❖ 문자열 접근을 보다 빠르게 하기 위하여 널문자를 삽입.!
❖ XML은 문자열 끝 다음 문자는 < 기호로 구분됨.
< n > T h e n o d e t e x t 0 / n >
포인터0xabc3, 길이 130xabc0
In-place parsing - 문자 표현 처리
❖ 문자열이 표현과 다른 경우 파싱중 처리.!
❖ `line1xDxAline2xDline3xAxA` 을

line1xAline2xAline3xAxA` 로 변환.!
❖ 문자 참조 확장 - &#97; 을 a 로 변환.!
❖ 개체 참조 확장 - &lt; (<), &gt;(>), &quot;(“), &apos;(‘);
&amp;(&)!
❖ 특성 값 정규화(Attribute-value normalization) - 모든 공
백문자를 빈칸으로 변환.
In-place parsing - 문자 표현 처리
❖ 변환 때문에 물자열이 더 길어져서는 안된다.!
❖ 변환 결과가 더 길면 문서 자료를 덮어 쓸 수 있기 때문.
< n > A & # 3 2 ; & l t ; B . < / n >0xabc0
< n > A < B . 0 l t ; B . < / n >0xabc0
In-place parsing - Copy-on-Write
❖ memory-mapped file I/O 을 사용.!
❖ 널종료와 텍스트 변환을 지원하기 위해 Copy-on-Write 방식을 적
용하여 원본 파일이 변경되는 것을 막음.!
❖ 프로세스 주소 공간에 직접 대응 시키므로 메모리 복사를 피할
수 있음.!
❖ 파일이 캐시되지 않은 경우 커널이 로딩하므로 입출력과 파싱이
병렬적으로 진행.!
❖ 수정된 페이지만 물리적 메모리에 할당되므로 메모리 소비를 줄
일 수 있음.
문자별 연산의 최적화

Optimizing character-wise operations
❖ 문자 하나에 소비된 평균 프로세서 주기(cycle) 수이다.!
❖ 문자 집합 소속 여부 검출

한 문자가 어떤 문자 집합에 속하는지 판정하는 것.
! enum chartype_t!
! {!
! ! ct_parse_pcdata = 1,! // 0, &, r, <!
! ! ct_parse_attr = 2,!! // 0, &, r, ', "!
! ! ct_parse_attr_ws = 4,! // 0, &, r, ', ", n, tab!
! ! ct_space = 8,! ! ! // r, n, space, tab!
! ! ct_parse_cdata = 16,! // 0, ], >, r!
! ! ct_parse_comment = 32,!// 0, -, >, r!
! ! ct_symbol = 64,! ! ! // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .!
! ! ct_start_symbol = 128! // Any symbol > 127, a-z, A-Z, _, :!
! };!
!
! static const unsigned char chartype_table[256] =!
! {!
! ! 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15!
! ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31!
! ! 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47!
! ! 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63!
! ! 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79!
! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95!
! ! 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111!
! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127!
!
! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+!
! ! … … …!
! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192!
! };!
!
! bool ischartype_utf8(char c, chartype_t ct){!
! ! return ct & chartype_table[(unsigned char)c];!
! }!
특정 구간의 모든 문자
❖ 주어진 문자가 숫자인지 판정하는 함수!
❖ bool isdigit(char ch) { return (ch >= '0' && ch <= '9'); }!
❖ bool isdigit(char ch) { return (unsigned)(ch - '0') < 10; }
UTF-8 바이트열
❖ 연속된 4 바이트가 ASCII 기호를 나타내는 UTF-8 바이트
열인지 판별하는 코드.!
❖ (*(const uint32_t*)data & 0x80808080) == 0
표준 라이브러리 is*() 함수
❖ 성능이 중요한 코드에서는 isalpha()등을 피해야 함.!
❖ locale 이 “C” 인지 점검하는 과정때문.
문자열 변환의 최적화
Optimizing string transformations
❖ 문자열 값을 읽고 변환하는 과정에서 시간 소비가 크다.!
❖ A&#32;&lt; B.!
❖ A < B.
PCDATA 파싱 함수
❖ bool 플래그 2개 -> 4개 변형.!
❖ 문자들은 문자 집합 판정 이
용.
template <bool opt_eol, bool opt_escape> struct!
! strconv_pcdata_impl {!
! static char_t* parse(char_t* s) {!
! gap g;!
! while (true) {!
! while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;!
! if (*s == '<') { // PCDATA ends here!
! *g.flush(s) = 0;!
! return s + 1;!
! } else if (opt_eol && *s == 'r') { // 0x0d or 0x0d 0x0a pair!
! *s++ = 'n'; // replace first one with 0x0a!
! if (*s == 'n') g.push(s, 1);!
! } else if (opt_escape && *s == '&') {!
! s = strconv_escape(/s, g);!
! } else if (*s == 0) {!
! return s;!
! } else {!
! ++s;!
! }!
! }!
! }!
! };!
PCDATA 틈(GAP) 관리
❖ &quot; 를 “ 로 대체하면 문자 다섯개의 틈이 생김.!
❖ 두 틈을 병합 - 기존 틈과 새 틈 사이 자료를 앞으로 옮김.!
❖ 읽기/쓰기 포인터보다 좀 더 빠르게 병합(memmove)
제어 흐름의 최적화
Optimizing control flow
❖ 재귀적 하강 파서(recursive-descent parser) 형태에서 성
능 향상을 위해 재귀를 반복 루프로 변경.!
❖ 노드 커서는 스택방식으로 동작.!
❖ 스택 공간 소비량이 입력 문서와 무관하게 일정.!
❖ 안정성을 증가.!
❖ 잠재적인 비싼 함수 호출을 피함. ???
분기 순서와 코드 국소성
❖ 자주 실행되는 부분(태그이름,속성)과 거의 실행되지 않
는 부분(DOCTYPE)!
❖ 처리 확률 - ‘<‘ 문자 다음 ‘태그 이름’, ‘/‘, ‘!’, ‘?’ 순의 확률
로 나타남.!
❖ 코드 조각들의 확률에 따라 재배치!
❖ 인라인 코드량을 제한.
❖ 조건 분기들을 확률이 높은 거에서 낮은 것 순서로 재배치.!
❖ 평균적인 조건 판정 및 분기 수행 횟수가 최소화.
! if (data[0] == '<')!
! {!
! if (data[1] == '!') { ... }!
! else if (data[1] == '/') { ... }!
! else if (data[1] == '?') { ... }!
! else { /* start-tag or unrecognized tag */ }!
! }!
!
! if (data[0] == '<')!
! {!
! if (PUGI__IS_CHARTYPE(data[1], ct_start_symbol)) { /* start-tag */ }!
! else if (data[1] == '/') { ... }!
! else if (data[1] == '!') { ... }!
! else if (data[1] == '?') { ... }!
! else { /* unrecognized tag */ }!
! }!
메모리 안정성 보장
❖ 버퍼 오버플로우를 막기 위해.!
❖ 현재 읽기와 버퍼 끝을 비교.!
❖ 하나의 레지스터가 더 필요.!
❖ 함수 호출시 현재 위치와 끝위치를 전달할 포인터 필요!
❖ 널문자 처리.!
❖ 입력 버퍼와 버퍼 크기를 전달하는 경우 사용의 불편함
발생.
DOM 자료 구조
❖ 연결 목록 기반 접근 방식을 사용하
는 노드 수정은 O(1).!
❖ 연결 목록 접근 방식- 고정 크기 할
당을 위한 빠른 메모리 할당자를 설
계하는 것이 임의 크기 할당자보다
쉽다.!
❖ 메모리 절약 - last_child 제거,
prev_sibling_cyclic 으로 대체O(1).
struct Node {!
Node* first_child;!
Node* last_child;!
Node* prev_sibling;!
Node* next_sibling;!
};!
struct Node {!
Node* first_child;!
Node* prev_sibling_cyclic;!
Node* next_sibling;!
};!
Node* last_child(Node* node) {!
return (node->first_child) ?!
node->first_child->prev_sibling_cyclic : NULL;!
}!
!
Node* prev_sibling(Node* node) {!
return (/node->prev_sibling_cyclic->next_sibling) ?!
node->prev_sibling_cyclic : NULL;!
}!
스택 기반 메모리 할당
❖ 가변 크기 문자열 할당.!
❖ 할당 국소성을 유지.!
❖ DOM 파괴 속도을 위한 메모리 해제.
스택 할당자
const size_t allocator_page_size = 32768;!
struct allocator_page {!
allocator_page* next_page;!
size_t offset;!
char data[allocator_page_size];!
};!
struct allocator_state {!
allocator_page* current;!
};!
!
void* allocate_new_page_data(size_t size) {!
size_t extra_size = (size >
allocator_page_size) ?!
size - allocator_page_size : 0;!
return malloc(sizeof(allocator_page) +
extra_size);!
}
void* allocate_oob(allocator_state* state,
size_t size) {!
allocator_page* page =
(allocator_page*)allocate_new_page_data(siz
e);!
// add page to page list!
page->next_page = state->current;!
state->current = page;!
// user data is located at the beginning
of the page!
page->offset = size;!
return page->data;!
}!
!
void* allocate(allocator_state* state,
size_t size) {!
if (state->current->offset + size <=
allocator_page_size) {!
void* result = state->current->data +
state->current->offset;!
state->current->offset += size;!
return result;!
}!
return allocate_oob(state, size);!
}!
스택 기반 할당자의 메모리 해제 지원
❖ 메모리 해제와 재사용을 위해 참조 카운트 방식 도입.!
❖ 모든 페이지는 32바이트 경계로 정렬되고 모든 페이지 포인터의
하위 다섯 비트는 항상 0이다. ???!
❖ 5비트에 XML 메타 데이터를 저장.!
❖ 할당된 요소의 위치를 페이지 시작 위치를 기준으로 오프셋으로
저장.!
❖ 페이지 포인터의 주소 => 

(allocator_page*)((char*)(object) -object->offset -
offsetof(allocator_page, data))

More Related Content

PDF
파이썬 파일처리 및 문자열 처리
PDF
DDD-07-Using The Language
PDF
3부. 더 심층적인 통찰력을 향한 리팩터링 (8장 도약)
PDF
Ddd ch12-13
PPTX
도메인 객체의 생명주기
PDF
14 strategy design
PDF
2011년 KTH H3 컨퍼런스 Track B, 세션4 "Advanced Git" by A.J
PDF
Netflix suro begins
파이썬 파일처리 및 문자열 처리
DDD-07-Using The Language
3부. 더 심층적인 통찰력을 향한 리팩터링 (8장 도약)
Ddd ch12-13
도메인 객체의 생명주기
14 strategy design
2011년 KTH H3 컨퍼런스 Track B, 세션4 "Advanced Git" by A.J
Netflix suro begins

Similar to Ch4 pugixml (8)

PPTX
Programming skills 1부
PDF
04장 고급변수 사용
PDF
Http 완벽 가이드(2장 url과 리소스)
PDF
[Kgc2013] 모바일 엔진 개발기
PDF
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
PDF
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
PDF
[전파교육] css day 2014
PPT
Daejeon IT Developer Conference Hibernate3
Programming skills 1부
04장 고급변수 사용
Http 완벽 가이드(2장 url과 리소스)
[Kgc2013] 모바일 엔진 개발기
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[전파교육] css day 2014
Daejeon IT Developer Conference Hibernate3
Ad

More from Kyungryul KIM (20)

PDF
Node ch12
PDF
11.scripting
PDF
32 osx app_release
PDF
Meteor ddp
PDF
Cocos2dx 7.1-7.2
PDF
Cocos2 d x-7.3_4
PDF
Cocos2d x-ch5-1
PDF
Coco2d x
PDF
23 drag drop
PDF
Hadoop ch5
PDF
전문검색기술도전
PDF
Nib_NSWindowController
PDF
PDF
서버인프라를지탱하는기술5 1 2
PDF
Chaper24 languages high_and_low
PDF
Ch22 운영체제
PDF
Mibis ch20
PDF
Mibis ch15
PDF
Mibis ch8
PDF
Mibis ch4
Node ch12
11.scripting
32 osx app_release
Meteor ddp
Cocos2dx 7.1-7.2
Cocos2 d x-7.3_4
Cocos2d x-ch5-1
Coco2d x
23 drag drop
Hadoop ch5
전문검색기술도전
Nib_NSWindowController
서버인프라를지탱하는기술5 1 2
Chaper24 languages high_and_low
Ch22 운영체제
Mibis ch20
Mibis ch15
Mibis ch8
Mibis ch4
Ad

Ch4 pugixml

  • 1. 제 4장 빛의 속도록 
 XML 파싱하기 김경렬
  • 2. XML 파싱 모형. ❖ SAX(Simple API for XML) - 스트림과 ‘태그 시작, 끝, 문 자자료’등의 콜백으로 데이터 처리.! ❖ Pull Parsing - SAX 유사, iterator 객체를 통해 제어.! ❖ DOM(Document Object Model) - 입력을 문서 객체로 변 환후 처리.
  • 3. pugixml DOM 파서 ❖ 메모리 안에 들어갈 정도로 작은 문서.! ❖ 방문할 노드들이 서로 참조하는 복잡한 구조를 가진 문서! ❖ 복잡한 방식으로 변환해야 하는 문서.
  • 4. pugixml 설계상의 선택 ❖ 아주 빠르고 가벼운 DOM 기반 XML 조작 라이브러리를 목표로 개발.! ❖ 성능과 XML 검증의 절충점.! ❖ well-formed 검증.! ❖ DTD(Document Type Declaration)은 검증 않함.! ❖ 종종 well-formed 가 아닌 경우도 성공으로 처리.
  • 5. 파싱 ❖ 토큰 스트림 대신 문자 스트림에 대해 파싱을 수행.! ❖ UTF-8 문자만 지원.! ❖ 제자리 파싱(In-place parsing) - 스트림에 있는 자료를 직 접 처리하는 방식.
 문자열 복사를 최소화하기 위해.
  • 6. In-place parsing ❖ 문자열을 만나면 그 문자열의 포인터와 길이를 저장.! ❖ 성능 좋아지지만, 메모리 사용량은 증가.
 - 원본 스트림 유지. < n > T h e n o d e t e x t < / n > 포인터0xabc3, 길이 130xabc0
  • 7. In-place parsing - 널문자 처리 ❖ 문자열 접근을 보다 빠르게 하기 위하여 널문자를 삽입.! ❖ XML은 문자열 끝 다음 문자는 < 기호로 구분됨. < n > T h e n o d e t e x t 0 / n > 포인터0xabc3, 길이 130xabc0
  • 8. In-place parsing - 문자 표현 처리 ❖ 문자열이 표현과 다른 경우 파싱중 처리.! ❖ `line1xDxAline2xDline3xAxA` 을
 line1xAline2xAline3xAxA` 로 변환.! ❖ 문자 참조 확장 - &#97; 을 a 로 변환.! ❖ 개체 참조 확장 - &lt; (<), &gt;(>), &quot;(“), &apos;(‘); &amp;(&)! ❖ 특성 값 정규화(Attribute-value normalization) - 모든 공 백문자를 빈칸으로 변환.
  • 9. In-place parsing - 문자 표현 처리 ❖ 변환 때문에 물자열이 더 길어져서는 안된다.! ❖ 변환 결과가 더 길면 문서 자료를 덮어 쓸 수 있기 때문. < n > A & # 3 2 ; & l t ; B . < / n >0xabc0 < n > A < B . 0 l t ; B . < / n >0xabc0
  • 10. In-place parsing - Copy-on-Write ❖ memory-mapped file I/O 을 사용.! ❖ 널종료와 텍스트 변환을 지원하기 위해 Copy-on-Write 방식을 적 용하여 원본 파일이 변경되는 것을 막음.! ❖ 프로세스 주소 공간에 직접 대응 시키므로 메모리 복사를 피할 수 있음.! ❖ 파일이 캐시되지 않은 경우 커널이 로딩하므로 입출력과 파싱이 병렬적으로 진행.! ❖ 수정된 페이지만 물리적 메모리에 할당되므로 메모리 소비를 줄 일 수 있음.
  • 11. 문자별 연산의 최적화
 Optimizing character-wise operations ❖ 문자 하나에 소비된 평균 프로세서 주기(cycle) 수이다.! ❖ 문자 집합 소속 여부 검출
 한 문자가 어떤 문자 집합에 속하는지 판정하는 것.
  • 12. ! enum chartype_t! ! {! ! ! ct_parse_pcdata = 1,! // 0, &, r, <! ! ! ct_parse_attr = 2,!! // 0, &, r, ', "! ! ! ct_parse_attr_ws = 4,! // 0, &, r, ', ", n, tab! ! ! ct_space = 8,! ! ! // r, n, space, tab! ! ! ct_parse_cdata = 16,! // 0, ], >, r! ! ! ct_parse_comment = 32,!// 0, -, >, r! ! ! ct_symbol = 64,! ! ! // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .! ! ! ct_start_symbol = 128! // Any symbol > 127, a-z, A-Z, _, :! ! };! ! ! static const unsigned char chartype_table[256] =! ! {! ! ! 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15! ! ! 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31! ! ! 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47! ! ! 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63! ! ! 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79! ! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95! ! ! 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111! ! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127! ! ! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+! ! ! … … …! ! ! 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192! ! };! ! ! bool ischartype_utf8(char c, chartype_t ct){! ! ! return ct & chartype_table[(unsigned char)c];! ! }!
  • 13. 특정 구간의 모든 문자 ❖ 주어진 문자가 숫자인지 판정하는 함수! ❖ bool isdigit(char ch) { return (ch >= '0' && ch <= '9'); }! ❖ bool isdigit(char ch) { return (unsigned)(ch - '0') < 10; }
  • 14. UTF-8 바이트열 ❖ 연속된 4 바이트가 ASCII 기호를 나타내는 UTF-8 바이트 열인지 판별하는 코드.! ❖ (*(const uint32_t*)data & 0x80808080) == 0
  • 15. 표준 라이브러리 is*() 함수 ❖ 성능이 중요한 코드에서는 isalpha()등을 피해야 함.! ❖ locale 이 “C” 인지 점검하는 과정때문.
  • 16. 문자열 변환의 최적화 Optimizing string transformations ❖ 문자열 값을 읽고 변환하는 과정에서 시간 소비가 크다.! ❖ A&#32;&lt; B.! ❖ A < B.
  • 17. PCDATA 파싱 함수 ❖ bool 플래그 2개 -> 4개 변형.! ❖ 문자들은 문자 집합 판정 이 용. template <bool opt_eol, bool opt_escape> struct! ! strconv_pcdata_impl {! ! static char_t* parse(char_t* s) {! ! gap g;! ! while (true) {! ! while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;! ! if (*s == '<') { // PCDATA ends here! ! *g.flush(s) = 0;! ! return s + 1;! ! } else if (opt_eol && *s == 'r') { // 0x0d or 0x0d 0x0a pair! ! *s++ = 'n'; // replace first one with 0x0a! ! if (*s == 'n') g.push(s, 1);! ! } else if (opt_escape && *s == '&') {! ! s = strconv_escape(/s, g);! ! } else if (*s == 0) {! ! return s;! ! } else {! ! ++s;! ! }! ! }! ! }! ! };!
  • 18. PCDATA 틈(GAP) 관리 ❖ &quot; 를 “ 로 대체하면 문자 다섯개의 틈이 생김.! ❖ 두 틈을 병합 - 기존 틈과 새 틈 사이 자료를 앞으로 옮김.! ❖ 읽기/쓰기 포인터보다 좀 더 빠르게 병합(memmove)
  • 19. 제어 흐름의 최적화 Optimizing control flow ❖ 재귀적 하강 파서(recursive-descent parser) 형태에서 성 능 향상을 위해 재귀를 반복 루프로 변경.! ❖ 노드 커서는 스택방식으로 동작.! ❖ 스택 공간 소비량이 입력 문서와 무관하게 일정.! ❖ 안정성을 증가.! ❖ 잠재적인 비싼 함수 호출을 피함. ???
  • 20. 분기 순서와 코드 국소성 ❖ 자주 실행되는 부분(태그이름,속성)과 거의 실행되지 않 는 부분(DOCTYPE)! ❖ 처리 확률 - ‘<‘ 문자 다음 ‘태그 이름’, ‘/‘, ‘!’, ‘?’ 순의 확률 로 나타남.! ❖ 코드 조각들의 확률에 따라 재배치! ❖ 인라인 코드량을 제한.
  • 21. ❖ 조건 분기들을 확률이 높은 거에서 낮은 것 순서로 재배치.! ❖ 평균적인 조건 판정 및 분기 수행 횟수가 최소화. ! if (data[0] == '<')! ! {! ! if (data[1] == '!') { ... }! ! else if (data[1] == '/') { ... }! ! else if (data[1] == '?') { ... }! ! else { /* start-tag or unrecognized tag */ }! ! }! ! ! if (data[0] == '<')! ! {! ! if (PUGI__IS_CHARTYPE(data[1], ct_start_symbol)) { /* start-tag */ }! ! else if (data[1] == '/') { ... }! ! else if (data[1] == '!') { ... }! ! else if (data[1] == '?') { ... }! ! else { /* unrecognized tag */ }! ! }!
  • 22. 메모리 안정성 보장 ❖ 버퍼 오버플로우를 막기 위해.! ❖ 현재 읽기와 버퍼 끝을 비교.! ❖ 하나의 레지스터가 더 필요.! ❖ 함수 호출시 현재 위치와 끝위치를 전달할 포인터 필요! ❖ 널문자 처리.! ❖ 입력 버퍼와 버퍼 크기를 전달하는 경우 사용의 불편함 발생.
  • 23. DOM 자료 구조 ❖ 연결 목록 기반 접근 방식을 사용하 는 노드 수정은 O(1).! ❖ 연결 목록 접근 방식- 고정 크기 할 당을 위한 빠른 메모리 할당자를 설 계하는 것이 임의 크기 할당자보다 쉽다.! ❖ 메모리 절약 - last_child 제거, prev_sibling_cyclic 으로 대체O(1). struct Node {! Node* first_child;! Node* last_child;! Node* prev_sibling;! Node* next_sibling;! };! struct Node {! Node* first_child;! Node* prev_sibling_cyclic;! Node* next_sibling;! };!
  • 24. Node* last_child(Node* node) {! return (node->first_child) ?! node->first_child->prev_sibling_cyclic : NULL;! }! ! Node* prev_sibling(Node* node) {! return (/node->prev_sibling_cyclic->next_sibling) ?! node->prev_sibling_cyclic : NULL;! }!
  • 25. 스택 기반 메모리 할당 ❖ 가변 크기 문자열 할당.! ❖ 할당 국소성을 유지.! ❖ DOM 파괴 속도을 위한 메모리 해제.
  • 26. 스택 할당자 const size_t allocator_page_size = 32768;! struct allocator_page {! allocator_page* next_page;! size_t offset;! char data[allocator_page_size];! };! struct allocator_state {! allocator_page* current;! };! ! void* allocate_new_page_data(size_t size) {! size_t extra_size = (size > allocator_page_size) ?! size - allocator_page_size : 0;! return malloc(sizeof(allocator_page) + extra_size);! } void* allocate_oob(allocator_state* state, size_t size) {! allocator_page* page = (allocator_page*)allocate_new_page_data(siz e);! // add page to page list! page->next_page = state->current;! state->current = page;! // user data is located at the beginning of the page! page->offset = size;! return page->data;! }! ! void* allocate(allocator_state* state, size_t size) {! if (state->current->offset + size <= allocator_page_size) {! void* result = state->current->data + state->current->offset;! state->current->offset += size;! return result;! }! return allocate_oob(state, size);! }!
  • 27. 스택 기반 할당자의 메모리 해제 지원 ❖ 메모리 해제와 재사용을 위해 참조 카운트 방식 도입.! ❖ 모든 페이지는 32바이트 경계로 정렬되고 모든 페이지 포인터의 하위 다섯 비트는 항상 0이다. ???! ❖ 5비트에 XML 메타 데이터를 저장.! ❖ 할당된 요소의 위치를 페이지 시작 위치를 기준으로 오프셋으로 저장.! ❖ 페이지 포인터의 주소 => 
 (allocator_page*)((char*)(object) -object->offset - offsetof(allocator_page, data))