diff --git a/doc/concept/polygon.qbk b/doc/concept/polygon.qbk index 14f040ce8..a2de9fd6a 100644 --- a/doc/concept/polygon.qbk +++ b/doc/concept/polygon.qbk @@ -44,8 +44,8 @@ above). but holes are allowed in __boost_geometry__ polygons). * If the polygons underlying `ring_type` is defined as clockwise, the exterior ring must have the clockwise orientation, and any interior ring must be - counter clockwise. If the `ring_type` is defined counter clockwise, it is - vice versa. + reversed w.r.t. the defined orientation (so: counter clockwise for clockwise exterior rings). + If the `ring_type` is defined counter clockwise, it is vice versa. * If the polygons underlying `ring_type` is defined as closed, all rings must be closed: the first point must be spatially equal to the last point. * The interior is a connected point set. diff --git a/doc/doxy/Doxyfile b/doc/doxy/Doxyfile index 50a390a58..e75f5a84c 100644 --- a/doc/doxy/Doxyfile +++ b/doc/doxy/Doxyfile @@ -39,7 +39,6 @@ TAB_SIZE = 8 # \return* for various return cases ALIASES = qbk{1}="\xmlonly \1 \endxmlonly" \ qbk{2}="\xmlonly \2 \endxmlonly" \ - qbk_skip="\xmlonly \endxmlonly" \ brief_calc{1}="Calculates the \1 of a geometry" \ brief_calc2{1}="Calculate the \1 of two geometries" \ brief_calc2{2}="Calculate the \1 \2 two geometries" \ @@ -56,7 +55,7 @@ ALIASES = qbk{1}="\xmlonly \1 \endxmlonly" \ tparam_box_or_segment="Any type fulfilling a Box Concept or a Segment Concept" \ tparam_calculation="numeric type for calculation (e.g. high precision); if [*void] then it is extracted automatically from the coordinate type and (if necessary) promoted to floating point" \ tparam_container="container type, for example std::vector, std::deque" \ - tparam_dimension_required="Dimension, this template parameter is required. Should contain \[0 .. n-1\] for an n-dimensional geometry" \ + tparam_dimension_required="Dimension, this template parameter is required. Should contain \\[0 .. n-1\\] for an n-dimensional geometry" \ tparam_first_point="first point type" \ tparam_functor="Function or class with operator()" \ tparam_output_collection="output collection, either a multi-geometry, or a std::vector / std::deque etc" \ @@ -159,7 +158,6 @@ GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = NO -SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages @@ -254,7 +252,6 @@ HTML_FILE_EXTENSION = .html HTML_HEADER = doxygen_input/ggl_doxygen_header.html HTML_FOOTER = doxygen_input/ggl_doxygen_footer.html HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Generated documentation, by Doxygen" diff --git a/doc/doxy/doxygen_input/sourcecode/doxygen_4.cpp b/doc/doxy/doxygen_input/sourcecode/doxygen_4.cpp index 203d10f5f..b6fdecb73 100644 --- a/doc/doxy/doxygen_input/sourcecode/doxygen_4.cpp +++ b/doc/doxy/doxygen_input/sourcecode/doxygen_4.cpp @@ -18,9 +18,9 @@ OBSOLETE #include #include -#include +#include -#include +#include static const int wkt_countries_count = 1; diff --git a/doc/doxy/doxygen_output/html/doxygen.css b/doc/doxy/doxygen_output/html/doxygen.css index 74445fe1f..4f78a1bf0 100644 --- a/doc/doxy/doxygen_output/html/doxygen.css +++ b/doc/doxy/doxygen_output/html/doxygen.css @@ -1,13 +1,12 @@ -/* The standard CSS for doxygen */ +/* The standard CSS for doxygen 1.8.3.1-20130324 */ body, table, div, p, dl { - font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; - font-size: 12px; + font: 400 14px/19px Roboto,sans-serif; } /* @group Heading Levels */ -h1 { +h1.groupheader { font-size: 150%; } @@ -17,14 +16,34 @@ h1 { margin: 10px 2px; } -h2 { - font-size: 120%; +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; } -h3 { +h3.groupheader { font-size: 100%; } +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + dt { font-weight: bold; } @@ -72,8 +91,6 @@ div.qindex, div.navtab{ background-color: #EBEFF6; border: 1px solid #A3B4D7; text-align: center; - margin: 2px; - padding: 2px; } div.qindex, div.navpath { @@ -123,12 +140,12 @@ a.el { a.elRef { } -a.code { - color: #4665A2; +a.code, a.code:visited { + color: #4665A2; } -a.codeRef { - color: #4665A2; +a.codeRef, a.codeRef:visited { + color: #4665A2; } /* @end */ @@ -137,20 +154,72 @@ dl.el { margin-left: -1cm; } -.fragment { - font-family: monospace, fixed; - font-size: 105%; +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; } -pre.fragment { - border: 1px solid #C4CFE5; +div.fragment { + padding: 4px; + margin: 4px; background-color: #FBFCFD; - padding: 4px 6px; - margin: 4px 8px 4px 2px; - overflow: auto; - word-wrap: break-word; - font-size: 9pt; - line-height: 125%; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; } div.ah { @@ -183,15 +252,15 @@ div.groupText { } body { - background: white; + background-color: white; color: black; margin: 0; } div.contents { margin-top: 10px; - margin-left: 10px; - margin-right: 5px; + margin-left: 12px; + margin-right: 8px; } td.indexkey { @@ -200,6 +269,8 @@ td.indexkey { border: 1px solid #C4CFE5; margin: 2px 0px 2px 0; padding: 2px 10px; + white-space: nowrap; + vertical-align: top; } td.indexvalue { @@ -292,6 +363,13 @@ span.vhdllogic { color: #ff0000 } +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + /* @end */ /* @@ -345,6 +423,24 @@ table.memberdecls { padding: 0px; } +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + .mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { @@ -359,8 +455,11 @@ table.memberdecls { color: #555; } -.memItemLeft, .memItemRight, .memTemplParams { - border-top: 1px solid #C4CFE5; +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; } .memItemLeft, .memTemplItemLeft { @@ -374,6 +473,7 @@ table.memberdecls { .memTemplParams { color: #4665A2; white-space: nowrap; + font-size: 80%; } /* @end */ @@ -406,15 +506,29 @@ table.memberdecls { padding: 0; margin-bottom: 10px; margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; } .memname { - white-space: nowrap; font-weight: bold; margin-left: 6px; } -.memproto { +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { border-top: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; @@ -422,45 +536,55 @@ table.memberdecls { color: #253555; font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); - /* opera specific markup */ - box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - border-top-right-radius: 8px; - border-top-left-radius: 8px; - /* firefox specific markup */ - -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - -moz-border-radius-topright: 8px; - -moz-border-radius-topleft: 8px; - /* webkit specific markup */ - -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - -webkit-border-top-right-radius: 8px; - -webkit-border-top-left-radius: 8px; background-image:url('nav_f.png'); background-repeat:repeat-x; background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; } -.memdoc { +.memdoc, dl.reflist dd { border-bottom: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; - padding: 2px 5px; + padding: 6px 10px 2px 10px; background-color: #FBFCFD; border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; /* opera specific markup */ - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); /* firefox specific markup */ - -moz-border-radius-bottomleft: 8px; - -moz-border-radius-bottomright: 8px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; - background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); /* webkit specific markup */ - -webkit-border-bottom-left-radius: 8px; - -webkit-border-bottom-right-radius: 8px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); - background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; } .paramkey { @@ -478,9 +602,13 @@ table.memberdecls { .paramname em { font-style: normal; } +.paramname code { + line-height: 14px; +} .params, .retval, .exception, .tparams { - border-spacing: 6px 2px; + margin-left: 0px; + padding-left: 0px; } .params .paramname, .retval .paramname { @@ -498,105 +626,116 @@ table.memberdecls { vertical-align: top; } +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} /* @end */ -/* @group Directory (tree) */ +/* these are for tree view when not used as main index */ -/* for the tree view */ - -.ftvtree { - font-family: sans-serif; - margin: 0px; +div.directory { + margin: 10px 0px; + border-top: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + width: 100%; } -/* these are for tree view when used as main index */ - -.directory { - font-size: 9pt; - font-weight: bold; - margin: 5px; +.directory table { + border-collapse:collapse; } -.directory h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; } -/* -The following two styles can be used to replace the root node title -with an image of your choice. Simply uncomment the next two styles, -specify the name of your image and be sure to set 'height' to the -proper pixel height of your image. -*/ - -/* -.directory h3.swap { - height: 61px; - background-repeat: no-repeat; - background-image: url("yourimage.gif"); -} -.directory h3.swap span { - display: none; -} -*/ - -.directory > h3 { - margin-top: 0; +.directory td.entry { + white-space: nowrap; + padding-right: 6px; } -.directory p { - margin: 0px; - white-space: nowrap; +.directory td.entry a { + outline:none; } -.directory div { - display: none; - margin: 0px; +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; } .directory img { vertical-align: -30%; } -/* these are for tree view when not used as main index */ - -.directory-alt { - font-size: 100%; - font-weight: bold; +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; } -.directory-alt h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; } -.directory-alt > h3 { - margin-top: 0; -} - -.directory-alt p { - margin: 0px; - white-space: nowrap; -} - -.directory-alt div { - display: none; - margin: 0px; -} - -.directory-alt img { - vertical-align: -30%; -} - -/* @end */ - div.dynheader { margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } address { @@ -606,6 +745,8 @@ address { table.doxtable { border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; } table.doxtable td, table.doxtable th { @@ -619,9 +760,72 @@ table.doxtable th { font-size: 110%; padding-bottom: 4px; padding-top: 5px; - text-align:left; } +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + .tabsearch { top: 0px; left: 10px; @@ -637,6 +841,7 @@ table.doxtable th { font-size: 11px; background-image:url('tab_b.png'); background-repeat:repeat-x; + background-position: 0 -5px; height:30px; line-height:30px; color:#8AA0CC; @@ -664,6 +869,10 @@ table.doxtable th { display:block; text-decoration: none; outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; } .navpath li.navelem a:hover @@ -702,7 +911,6 @@ div.summary a div.ingroups { font-size: 8pt; - padding-left: 5px; width: 50%; text-align: left; } @@ -731,47 +939,74 @@ dl padding: 0 0 0 10px; } -dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section { - border-left:4px solid; - padding: 0 0 0 6px; + margin-left: 0px; + padding-left: 0px; } dl.note { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #D0C000; } dl.warning, dl.attention { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #FF0000; } dl.pre, dl.post, dl.invariant { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #00D000; } dl.deprecated { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #505050; } dl.todo { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #00C0E0; } dl.test { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #3030E0; } dl.bug { + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; border-color: #C08050; } +dl.section dd { + margin-bottom: 6px; +} + + #projectlogo { text-align: center; @@ -833,3 +1068,117 @@ dl.bug font-weight: bold; } +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + diff --git a/doc/doxy/doxygen_output/html/doxygen.png b/doc/doxy/doxygen_output/html/doxygen.png index 635ed52fc..3ff17d807 100644 Binary files a/doc/doxy/doxygen_output/html/doxygen.png and b/doc/doxy/doxygen_output/html/doxygen.png differ diff --git a/doc/doxy/doxygen_output/html/tabs.css b/doc/doxy/doxygen_output/html/tabs.css index 21920562a..9cf578f23 100644 --- a/doc/doxy/doxygen_output/html/tabs.css +++ b/doc/doxy/doxygen_output/html/tabs.css @@ -3,6 +3,7 @@ width: 100%; z-index: 101; font-size: 13px; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; } .tabs2 { diff --git a/doc/generated/wkt_status.qbk b/doc/generated/wkt_status.qbk new file mode 100644 index 000000000..e4d8d3023 --- /dev/null +++ b/doc/generated/wkt_status.qbk @@ -0,0 +1,13 @@ +[heading Supported geometries] +[table +[[Geometry][Status]] +[[Point][ [$img/ok.png] ]] +[[Segment][ [$img/ok.png] ]] +[[Box][ [$img/ok.png] ]] +[[Linestring][ [$img/ok.png] ]] +[[Ring][ [$img/ok.png] ]] +[[Polygon][ [$img/ok.png] ]] +[[MultiPoint][ [$img/ok.png] ]] +[[MultiLinestring][ [$img/ok.png] ]] +[[MultiPolygon][ [$img/ok.png] ]] +] diff --git a/doc/geometry.qbk b/doc/geometry.qbk index 8059fe03a..d0c40eb16 100644 --- a/doc/geometry.qbk +++ b/doc/geometry.qbk @@ -12,8 +12,8 @@ [library Geometry [quickbook 1.5] - [authors [Gehrels, Barend], [Lalande, Bruno], [Loskot, Mateusz]] - [copyright 2009-2012 Barend Gehrels, Bruno Lalande, Mateusz Loskot] + [authors [Gehrels, Barend], [Lalande, Bruno], [Loskot, Mateusz], [Wulkiewicz, Adam]] + [copyright 2009-2013 Barend Gehrels, Bruno Lalande, Mateusz Loskot, Adam Wulkiewicz] [purpose Documentation of Boost.Geometry library] [license Distributed under the Boost Software License, Version 1.0. @@ -35,7 +35,8 @@ [def __geo__ Geographic] [def __rev__ Reversed polygon (coordinates not according their orientiation)] [def __empty__ Empty (e.g. polygon without points)] -[def __box__ Rectangle] +[def __box__ Box] +[def __rectangle__ Rectangle] [def __segment__ Segment] [def __point__ Point] [def __linestring__ Linestring] @@ -108,8 +109,7 @@ Boost.Geometry contains contributions by: * Akira Takahashi (adaption of Boost.Fusion) * Alfredo Correa (adaption of Boost.Array) -* Adam Wulkiewicz (spatial indexes) [footnote Currently an extension] -* Federico Fern\u00E1ndez (spatial indexes) [footnote Currently an extension] +* Federico Fern\u00E1ndez (preliminary version of R-tree spatial index) * Karsten Ahnert (patch for cross-track distance) [include imports.qbk] @@ -120,6 +120,10 @@ Boost.Geometry contains contributions by: [include design_rationale.qbk] [include compiling.qbk] +[section Spatial indexes] +[include index/index.qbk] +[endsect] + [section Indexes] [include matrix.qbk] [section Alphabetical Index] diff --git a/doc/html/img/index/rtree/disjoint.png b/doc/html/img/index/rtree/disjoint.png new file mode 100644 index 000000000..131a91586 Binary files /dev/null and b/doc/html/img/index/rtree/disjoint.png differ diff --git a/doc/html/img/index/rtree/intersects.png b/doc/html/img/index/rtree/intersects.png new file mode 100644 index 000000000..066a1dd80 Binary files /dev/null and b/doc/html/img/index/rtree/intersects.png differ diff --git a/doc/html/img/index/rtree/intersects_mpoly.png b/doc/html/img/index/rtree/intersects_mpoly.png new file mode 100644 index 000000000..f6172d210 Binary files /dev/null and b/doc/html/img/index/rtree/intersects_mpoly.png differ diff --git a/doc/html/img/index/rtree/intersects_poly.png b/doc/html/img/index/rtree/intersects_poly.png new file mode 100644 index 000000000..d87607857 Binary files /dev/null and b/doc/html/img/index/rtree/intersects_poly.png differ diff --git a/doc/html/img/index/rtree/intersects_ring.png b/doc/html/img/index/rtree/intersects_ring.png new file mode 100644 index 000000000..6af2c96a3 Binary files /dev/null and b/doc/html/img/index/rtree/intersects_ring.png differ diff --git a/doc/html/img/index/rtree/knn.png b/doc/html/img/index/rtree/knn.png new file mode 100644 index 000000000..f142919d8 Binary files /dev/null and b/doc/html/img/index/rtree/knn.png differ diff --git a/doc/html/img/index/rtree/linear.png b/doc/html/img/index/rtree/linear.png new file mode 100644 index 000000000..15cbd4c3e Binary files /dev/null and b/doc/html/img/index/rtree/linear.png differ diff --git a/doc/html/img/index/rtree/overlaps.png b/doc/html/img/index/rtree/overlaps.png new file mode 100644 index 000000000..70d77a120 Binary files /dev/null and b/doc/html/img/index/rtree/overlaps.png differ diff --git a/doc/html/img/index/rtree/path.png b/doc/html/img/index/rtree/path.png new file mode 100644 index 000000000..fa393abff Binary files /dev/null and b/doc/html/img/index/rtree/path.png differ diff --git a/doc/html/img/index/rtree/quadratic.png b/doc/html/img/index/rtree/quadratic.png new file mode 100644 index 000000000..9fedf85a7 Binary files /dev/null and b/doc/html/img/index/rtree/quadratic.png differ diff --git a/doc/html/img/index/rtree/rstar.png b/doc/html/img/index/rtree/rstar.png new file mode 100644 index 000000000..45308b361 Binary files /dev/null and b/doc/html/img/index/rtree/rstar.png differ diff --git a/doc/html/img/index/rtree/within.png b/doc/html/img/index/rtree/within.png new file mode 100644 index 000000000..44ab19e48 Binary files /dev/null and b/doc/html/img/index/rtree/within.png differ diff --git a/doc/html/index.html b/doc/html/index.html index b5ad714c8..e73e9fd8b 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -31,8 +31,10 @@

Mateusz Loskot

-
+

+Adam Wulkiewicz +

+

Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -47,6 +49,8 @@

Quick Start
Design Rationale
Compilation
+
Spatial indexes
+
R-tree
Indexes
Reference matrix
@@ -66,6 +70,7 @@
Exceptions
Iterators
Models
+
Spatial indexes
Strategies
Views
@@ -89,27 +94,15 @@ Alfredo Correa (adaption of Boost.Array)
  • - Adam Wulkiewicz (spatial indexes) [1] -
  • -
  • - Federico Fernández (spatial indexes) [2] + Federico Fernández (preliminary version of R-tree spatial index)
  • Karsten Ahnert (patch for cross-track distance)
  • -
    -

    -

    [1] - Currently an extension -

    -

    [2] - Currently an extension -

    -
    - +

    Last revised: August 21, 2012 at 16:43:26 GMT

    Last revised: May 12, 2013 at 10:55:03 GMT


    diff --git a/doc/index/Doxyfile b/doc/index/Doxyfile new file mode 100644 index 000000000..597de34d0 --- /dev/null +++ b/doc/index/Doxyfile @@ -0,0 +1,332 @@ +# Doxyfile 1.8.1.2 +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Boost.Geometry.Index" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +BUILTIN_STL_SUPPORT = YES +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../../../../boost/geometry/index/ \ + ../../../../boost/geometry/index/adaptors +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html_by_doxygen +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = "BOOST_RV_REF(T)=T &&" \ + "BOOST_COPY_ASSIGN_REF(T)=T const &" +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/doc/index/Jamfile.v2 b/doc/index/Jamfile.v2 new file mode 100644 index 000000000..e6f507006 --- /dev/null +++ b/doc/index/Jamfile.v2 @@ -0,0 +1,32 @@ +# Boost.Geometry Index +# +# Copyright (c) 2011-2012 Adam Wulkiewicz. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project geometry_index/doc ; + +import boostbook ; +import quickbook ; + +boostbook geometry_index-doc + : + index.qbk + : + Jamfile.v2 + generated/rtree.qbk + + html + pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html + chunk.section.depth=2 + chunk.first.sections=1 + toc.section.depth=3 + toc.max.depth=2 + generate.section.toc.level=2 + boost.root=http://www.boost.org/doc/libs/release + + enable_index + $(here) + ; diff --git a/doc/index/imports.qbk b/doc/index/imports.qbk new file mode 100644 index 000000000..5d81a7639 --- /dev/null +++ b/doc/index/imports.qbk @@ -0,0 +1,17 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[import src/examples/rtree/quick_start.cpp] +[import src/examples/rtree/polygons_vector.cpp] +[import src/examples/rtree/polygons_shared_ptr.cpp] +[import src/examples/rtree/variants_map.cpp] +[import src/examples/rtree/value_shared_ptr.cpp] +[import src/examples/rtree/value_index.cpp] +[import src/examples/rtree/interprocess.cpp] diff --git a/doc/index/index.qbk b/doc/index/index.qbk new file mode 100644 index 000000000..5766162af --- /dev/null +++ b/doc/index/index.qbk @@ -0,0 +1,38 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[/library Geometry Index + [quickbook 1.5] + [authors [Wulkiewicz, Adam]] + [copyright 2011-2013 Adam Wulkiewicz] + [purpose Documentation of Boost.Geometry Index library] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@http://www.boost.org/LICENSE_1_0.txt]) + ] + [id geometry] + [category geometry] +/] + +[def __boost_geometry_index__ Boost.Geometry.Index] + +[def __rtree__ R-tree] + +[def __value__ Value] +[def __parameters__ Parameters] +[def __allocator__ Allocator] +[def __indexable__ Indexable] + +[include imports.qbk] + +[/include introduction.qbk/] + +[include rtree.qbk] diff --git a/doc/index/introduction.qbk b/doc/index/introduction.qbk new file mode 100644 index 000000000..0c7e0b7a8 --- /dev/null +++ b/doc/index/introduction.qbk @@ -0,0 +1,19 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Introduction] + +The __boost_geometry_index__ is intetended to gather containers (spatial indexes) which may be used to accelerate spatial searching. +It is a part of the __boost_geometry__ library. In general, spatial indexes stores geometric objects' representations and +allows searching for objects occupying some space or close to some point in space. + +Currently, only one spatial index is implemented - __rtree__. + +[endsect] diff --git a/doc/index/make_qbk.py b/doc/index/make_qbk.py new file mode 100755 index 000000000..9185f3f10 --- /dev/null +++ b/doc/index/make_qbk.py @@ -0,0 +1,39 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# =========================================================================== +# Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. +# Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt)9 +# ============================================================================ + +import os, sys + +cmd = "doxygen_xml2qbk" +cmd = cmd + " --xml xml/%s.xml" +cmd = cmd + " --start_include boost/" +cmd = cmd + " --output_style alt" +cmd = cmd + " > generated/%s.qbk" + +os.system("doxygen Doxyfile") +os.system(cmd % ("classboost_1_1geometry_1_1index_1_1rtree", "rtree")) +os.system(cmd % ("group__rtree__functions", "rtree_functions")) + +os.system(cmd % ("structboost_1_1geometry_1_1index_1_1linear", "rtree_linear")) +os.system(cmd % ("structboost_1_1geometry_1_1index_1_1quadratic", "rtree_quadratic")) +os.system(cmd % ("structboost_1_1geometry_1_1index_1_1rstar", "rtree_rstar")) +os.system(cmd % ("classboost_1_1geometry_1_1index_1_1dynamic__linear", "rtree_dynamic_linear")) +os.system(cmd % ("classboost_1_1geometry_1_1index_1_1dynamic__quadratic", "rtree_dynamic_quadratic")) +os.system(cmd % ("classboost_1_1geometry_1_1index_1_1dynamic__rstar", "rtree_dynamic_rstar")) + +os.system(cmd % ("structboost_1_1geometry_1_1index_1_1indexable", "indexable")) +os.system(cmd % ("structboost_1_1geometry_1_1index_1_1equal__to", "equal_to")) + +os.system(cmd % ("group__predicates", "predicates")) +#os.system(cmd % ("group__nearest__relations", "nearest_relations")) +os.system(cmd % ("group__adaptors", "adaptors")) +os.system(cmd % ("group__inserters", "inserters")) + +#os.system("b2") diff --git a/doc/index/rtree.qbk b/doc/index/rtree.qbk new file mode 100644 index 000000000..46063c8f5 --- /dev/null +++ b/doc/index/rtree.qbk @@ -0,0 +1,21 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section R-tree] + +[include rtree/introduction.qbk] +[include rtree/quickstart.qbk] +[include rtree/creation.qbk] +[include rtree/query.qbk] +[include rtree/examples.qbk] +[include rtree/experimental.qbk] +[/include rtree/reference.qbk] + +[endsect] diff --git a/doc/index/rtree/creation.qbk b/doc/index/rtree/creation.qbk new file mode 100644 index 000000000..04aa9734b --- /dev/null +++ b/doc/index/rtree/creation.qbk @@ -0,0 +1,231 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Creation and modification] + +[section Template parameters] + +__rtree__ has 5 parameters: + + rtree, + EqualTo = index::equal_to, + Allocator = std::allocator > + +* `__value__` - type of object which will be stored in the container, +* `Parameters` - parameters type, inserting/splitting algorithm, +* `IndexableGetter` - function object translating `__value__` to `__indexable__` (`__point__` or `__box__`) which __rtree__ can handle, +* `EqualTo` - function object comparing `__value__`s, +* `Allocator` - `Value`s allocator, all allocators needed by the container are created from it. + +[endsect] + +[section Values and Indexables] + +__rtree__ may store `__value__`s of any type as long as passed function objects know how to interpret those `__value__`s, that is +extract an `__indexable__` that the __rtree__ can handle and compare `__value__`s. + +By default function objects `index::indexable` and `index::equal_to` are defined for some typically used `__value__` +types which may be stored without defining any additional classes. By default the rtree may store pure `__indexable__`s, pairs +and tuples. In the case of those two collection types, the `__indexable__` must be the first stored type. + +* `__indexable__ = __point__ | __box__` +* `__value__ = Indexable | std::pair<__indexable__, T> | tuple<__indexable__, ...>` + +By default `boost::tuple<...>` is supported on all compilers. If the compiler supports C++11 tuples and variadic templates +then `std::tuple<...>` may be used "out of the box" as well. + +Examples of default `__value__` types: + + geometry::model::point<...> + geometry::model::point_xy<...> + geometry::model::box<...> + std::pair, unsigned> + boost::tuple, int, float> + +The predefined `index::indexable` returns const reference to the `__indexable__` stored in the `__value__`. + +[important The translation is done quite frequently inside the continer - each time the rtree needs it. ] + +The predefined `index::equal_to`: + +* for `__point__` and `__box__` - compares `__value__`s with geometry::equals(). +* for `std::pair<...>` - compares both components of the `__value__`. The first value stored in the pair is compared before the second one. + If the value stored in the pair is a Geometry, `geometry::equals()` is used. For other types it uses `operator==()`. +* for `tuple<...>` - compares all components of the `__value__`. If the component is a `Geometry`, `geometry::equals()` + function is used. For other types it uses `operator==()`. + +[endsect] + +[section Balancing algorithms] + +[heading Compile-time] + +`__value__`s may be inserted to the __rtree__ in many various ways. Final internal structure +of the __rtree__ depends on algorithms used in the insertion process and parameters. The most important is +nodes' balancing algorithm. Currently, three well-known types of R-trees may be created. + +Linear - classic __rtree__ using balancing algorithm of linear complexity + + index::rtree< __value__, index::linear<16> > rt; + +Quadratic - classic __rtree__ using balancing algorithm of quadratic complexity + + index::rtree< __value__, index::quadratic<16> > rt; + +R*-tree - balancing algorithm minimizing nodes' overlap with forced reinsertions + + index::rtree< __value__, index::rstar<16> > rt; + +[heading Run-time] + +Balancing algorithm parameters may be passed to the __rtree__ in run-time. +To use run-time versions of the __rtree__ one may pass parameters which +names start with `dynamic_`. + + // linear + index::rtree<__value__, index::dynamic_linear> rt(index::dynamic_linear(16)); + + // quadratic + index::rtree<__value__, index::dynamic_quadratic> rt(index::dynamic_quadratic(16)); + + // rstar + index::rtree<__value__, index::dynamic_rstar> rt(index::dynamic_rstar(16)); + +The obvious drawback is a slightly slower __rtree__. + +[heading Non-default parameters] + +Non-default R-tree parameters are described in the reference. + +[endsect] + +[section Copying, moving and swapping] + +The __rtree__ is copyable and movable container. Move semantics is implemented using Boost.Move library +so it's possible to move the container on a compilers without rvalue references support. + + // default constructor + index::rtree< __value__, index::rstar<8> > rt1; + + // copy constructor + index::rtree< __value__, index::rstar<8> > rt2(r1); + + // copy assignment + rt2 = r1; + + // move constructor + index::rtree< __value__, index::rstar<8> > rt3(boost::move(rt1)); + + // move assignment + rt3 = boost::move(rt2); + + // swap + rt3.swap(rt2); + +[endsect] + +[section Inserting and removing Values] + +The following code creates an __rtree__ using quadratic balancing algorithm. + + using namespace boost::geometry; + typedef std::pair __value__; + index::rtree< __value__, index::quadratic<16> > rt; + +To insert or remove a `__value__' by method call one may use the following +code. + + __value__ v = std::make_pair(__box__(...), 0); + + rt.insert(v); + + rt.remove(v); + +To insert or remove a `__value__' by function call one may use the following +code. + + __value__ v = std::make_pair(__box__(...), 0); + + index::insert(rt, v); + + index::remove(rt, v); + +Typically you will perform those operations in a loop in order to e.g. insert +some number of `__value__`s corresponding to geometrical objects (e.g. `Polygons`) +stored in another container. + +[heading Additional interface] + +The __rtree__ allows creation, inserting and removing of Values from a range. The range may be passed as +[first, last) Iterators pair or as a Range. + + namespace bgi = boost::geometry::index; + typedef std::pair __value__; + typedef bgi::rtree< __value__, bgi::linear<32> > RTree; + + std::vector<__value__> values; + /* vector filling code, here */ + + // create R-tree with default constructor and insert values with insert(Value const&) + RTree rt1; + BOOST_FOREACH(__value__ const& v, values) + rt1.insert(v); + + // create R-tree with default constructor and insert values with insert(Iter, Iter) + RTree rt2; + rt2.insert(values.begin(), values.end()); + + // create R-tree with default constructor and insert values with insert(Range) + RTree rt3; + rt3.insert(values); + + // create R-tree with constructor taking Iterators + RTree rt4(values.begin(), values.end()); + + // create R-tree with constructor taking Range + RTree rt5(values); + + // remove values with remove(Value const&) + BOOST_FOREACH(__value__ const& v, values) + rt1.remove(v); + + // remove values with remove(Iter, Iter) + rt2.remove(values.begin(), values.end()); + + // remove values with remove(Range) + rt3.remove(values); + +[heading Insert iterator] + +There are functions like `std::copy()`, or __rtree__'s queries that copy values to an output iterator. +In order to insert values to a container in this kind of function insert iterators may be used. +Geometry.Index provide its own `bgi::insert_iterator` which is generated by +`bgi::inserter()` function. + + namespace bgi = boost::geometry::index; + typedef std::pair __value__; + typedef bgi::rtree< __value__, bgi::linear<32> > RTree; + + std::vector<__value__> values; + /* vector filling code, here */ + + // create R-tree and insert values from the vector + RTree rt1; + std::copy(values.begin(), values.end(), bgi::inserter(rt1)); + + // create R-tree and insert values returned by a query + RTree rt2; + rt1.spatial_query(Box(/*...*/), bgi::inserter(rt2)); + +[endsect] + +[endsect] [/ Creation and modification /] diff --git a/doc/index/rtree/examples.qbk b/doc/index/rtree/examples.qbk new file mode 100644 index 000000000..8b57bde7e --- /dev/null +++ b/doc/index/rtree/examples.qbk @@ -0,0 +1,41 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2013 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section:rtree_examples Examples] + +[section Quick start] +[rtree_quickstart] +[endsect] + +[section Index of polygons stored in vector] +[rtree_polygons_vector] +[endsect] + +[section Index of shared pointers to polygons] +[rtree_polygons_shared_ptr] +[endsect] + +[section Index of iterators of a map storing variant geometries] +[rtree_variants_map] +[endsect] + +[section Specializing index::indexable function object - storing shared pointers in the rtree] +[rtree_value_shared_ptr] +[endsect] + +[section Using IndexableGetter function object - storing indexes of external container's elements] +[rtree_value_index] +[endsect] + +[section Index stored in shared memory using Boost.Interprocess] +[rtree_interprocess] +[endsect] + +[endsect] diff --git a/doc/index/rtree/exception_safety.qbk b/doc/index/rtree/exception_safety.qbk new file mode 100644 index 000000000..8f1dbb6af --- /dev/null +++ b/doc/index/rtree/exception_safety.qbk @@ -0,0 +1,57 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Exception safety] + +In order to be exception-safe the __rtree__ requires: + +* exception-safe copy constructor and copy assignment of the `__value__`. +* exception-safe copy constructor and copy assignment of the `CoordinateType` used in the `Indexable`. +* nonthrowing copy constructor of the `Translator`. +* nonthrowing destructors of above types. + +[table +[[Operation] [exception-safety]] +[[`rtree()`] [ /nothrow/ ]] +[[`rtree(Iterator, Iterator)`] [ *strong* ]] +[[`~rtree()`] [ /nothrow/ ]] +[[][]] +[[`rtree(rtree const&)`] [ *strong* ]] +[[`operator=(rtree const&)`] [ *strong* ]] +[[][]] +[[`rtree(rtree &&)`] [ /nothrow/ ]] +[[`operator=(rtree &&)`] [ /nothrow/ or *strong* +[footnote /nothrow/ - if allocators are equal, *strong* - otherwise]]] +[[`swap(rtree &)`] [ /nothrow/ ]] +[[][]] +[[`insert(__value__)`] [ not safe +[footnote If this operation throws, the R-tree may be left in an inconsistent state, elements must not be inserted or removed, methods may return invalid data.]]] +[[`insert(Iterator, Iterator)`][ not safe ]] +[[`insert(Range)`] [ not safe ]] +[[`remove(__value__)`] [ not safe ]] +[[`remove(Iterator, Iterator)`][ not safe ]] +[[`remove(Range)`] [ not safe ]] +[[`clear()`] [ /nothrow/ ]] +[[][]] +[[`spatial_query(...)`] [ *strong* ]] +[[`nearest_query(...)`] [ *strong* ]] +[[`count(ValueOrIndexable)`] [ /nothrow/ ]] +[[][]] +[[`size()`] [ /nothrow/ ]] +[[`empty()`] [ /nothrow/ ]] +[[`box()`] [ /nothrow/ or *strong* +[footnote /nothrow/ - if `CoordinateType` has nonthrowing copy constructor, *strong* - otherwise]]] +[[][]] +[[`get_allocator()`] [ /nothrow/ ]] +[[`parameters()`] [ /nothrow/ ]] +[[`translator()`] [ /nothrow/ ]] +] + +[endsect] [/Exception safety/] diff --git a/doc/index/rtree/experimental.qbk b/doc/index/rtree/experimental.qbk new file mode 100644 index 000000000..71aae4f28 --- /dev/null +++ b/doc/index/rtree/experimental.qbk @@ -0,0 +1,110 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2013 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Experimental features] + +This section describes experimental features which are implemented but unavailable by default. +Be aware that they may not be released in the future or functionalities may be released but +behind different interface. + +To enable them one must define `BOOST_GEOMETRY_INDEX_DETAIL_EXPERIMENTAL` in compiler's command line or before +including spatial index. + +[heading Nearest query distance calculation] + +It is possible to define how distance to the non-point `__value__` should be calculated. To do this one may pass +a relation object instead of a Point to the nearest predicate, as follows: + + /* caluclate distance to the Indexables' nearest points */ + rtree.query(index::nearest(index::to_nearest(pt), k), std::back_inserter(returned_values)); // same as default + + /* caluclate distance to the Indexables' centroid */ + rtree.query(index::nearest(index::to_centroid(pt), k), std::back_inserter(returned_values)); + + /* caluclate distance to the Indexables' furthest points */ + rtree.query(index::nearest(index::to_furthest(pt), k), std::back_inserter(returned_values)); + +[heading Path query] + +Path query returns `k` first `__value__`s intersecting a path defined by a `Linestring`. The result of a query returning first 5 +values intersecting a path is presented below. Path's flow is denoted by blue arrows, returned values are orange. + +[$img/index/rtree/path.png] + +To perform this query one may pass a `path()` predicate taking a `Linestring` and maximum number of `__value__`s which +should be returned: + + rtree.query(index::path(linestring, k), std::back_inserter(returned_values)); + +[warning Only one distance predicate may be used in a query. This means that there can be only one `nearest()` or `path()` predicate passed. Passing more of them will result in compile-time error.] + +[heading Incremental queries] + +Sometimes there is a need to stop querying at some desired moment because for example the decision that query should find another value +is made after analysis of previously returned values. There can also be desirable to pause querying and resume it later. + +Currently, those kind of incremental queries are implemented as input (single pass) const iterators, relatively +big fat-iterators storing stack used in the tree-traversing process. Because the type of predicates passed +to the query varies, the type of the iterator varies as well. + +Therefore to use query iterators one must pass them to some function template, then types will be deduced +automatically. If iterators objects must be stored one may use Boost.Typeof library to retrieve a type from +an expression or use C++11 `auto` or `decltype`. + + /* function call */ + std::copy(rtree.qbegin(index::intersects(box)), rtree.qend(index::intersects(box)), std::back_inserter(returned_values)); + + /* Boost.Typeof */ + typedef BOOST_TYPEOF(rtree.qbegin(index::nearest(pt, 5))) const_query_iterator; + const_query_iterator first = rtree.qbegin(index::nearest(pt, 5)); + const_query_iterator last = rtree.qend(index::nearest(pt, 5)); + // ... + for ( ; first != last ; ++first ) + *first; // do domething with Value + + /* C++11 */ + auto first = rtree.qbegin(index::nearest(pt, 5)); + auto last = rtree.qend(index::nearest(pt, 5)); + // ... + for ( ; first != last ; ++first ) + *first; // do domething with Value + +`qend()` method is overloaded to return a different, lighter type of iterator which may be compared +with query iterator to check if the querying was finished. But since it has different type than the one returned by +`qbegin(Pred)` it can't be used with STL-like functions like `std::copy()` which expect that `first` and `last` +iterators have the same type. + + /* function call */ + template + void my_copy(First first, Last last, Out out) + { + for ( ; first != last ; ++out, ++first ) + *out = *first; + } + // ... + my_copy(rtree.qbegin(index::intersects(box)), rtree.qend(), std::back_inserter(returned_values)); + + /* Boost.Typeof */ + typedef BOOST_TYPEOF(rtree.qbegin(index::nearest(pt, 5))) const_query_iterator; + typedef BOOST_TYPEOF(rtree.qend()) end_iterator; + const_query_iterator first = rtree.qbegin(index::nearest(pt, 5)); + end_iterator last = rtree.qend(); + // ... + for ( ; first != last ; ++first ) + *first; // do domething with Value + + /* C++11 */ + auto first = rtree.qbegin(index::nearest(pt, 5)); + auto last = rtree.qend(); + // ... + for ( ; first != last ; ++first ) + *first; // do domething with Value + +[endsect] [/ Experimental features /] diff --git a/doc/index/rtree/introduction.qbk b/doc/index/rtree/introduction.qbk new file mode 100644 index 000000000..9d25d47a9 --- /dev/null +++ b/doc/index/rtree/introduction.qbk @@ -0,0 +1,68 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Introduction] + +__rtree__ is a tree data structure used for spatial searching. It was proposed by +Antonin Guttman in 1984 [footnote Guttman, A. (1984). /R-Trees: A Dynamic Index Structure for Spatial Searching/] +as an expansion of B-tree for multi-dimensional data. It may be used to store points or volumetric data in order to +perform a spatial query later. This query may return objects that are inside some area or are close to some point in space +[footnote Cheung, K.; Fu, A. (1998). /Enhanced Nearest Neighbour Search on the R-tree/]. + +The __rtree__ structure is presented on the image below. Each __rtree__'s node store a box descring the space occupied by +its children nodes. At the bottom of the structure, there are leaf-nodes which contains values +(geometric objects representations). + +[$img/index/rtree/rstar.png] + +The __rtree__ is a self-balanced data structure. The key part of balancing algorithm is node splitting algorithm +[footnote Greene, D. (1989). /An implementation and performance analysis of spatial data access methods/] +[footnote Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). /The R*-tree: an efficient and robust access method for points and rectangles/]. +Each algorithm produces different splits so the internal structure of a tree may be different for each one of them. +In general more complex algorithms analyses elements better and produces less overlapping nodes. In the searching process less nodes must be traversed +in order to find desired obejcts. On the other hand more complex analysis takes more time. In general faster inserting will result in slower searching +and vice versa. The performance of the R-tree depends on balancing algorithm, parameters and data inserted into the container. +Example structures of trees created by use of three different algorithms and operations time are presented below. Data used in benchmark was random, +non-overlapping boxes. + +[table +[[] [linear algorithm] [quadratic algorithm] [R*-tree]] +[[*Example structure*] [[$img/index/rtree/linear.png]] [[$img/index/rtree/quadratic.png]] [[$img/index/rtree/rstar.png]]] +[[*1M Values inserts*] [1.65s] [2.51s] [4.96s]] +[[*100k spatial queries*] [0.87s] [0.25s] [0.09s]] +[[*100k knn queries*] [3.25s] [1.41s] [0.51s]] +] + +[heading Implementation details] + +Key features of this implementation of the __rtree__ are: + +* capable to store arbitrary __value__ type, +* three different creation algorithms - linear, quadratic or rstar, +* parameters (including maximal and minimal number of elements) may be passed as compile- or run-time parameters, +* advanced queries - e.g. search for 5 nearest values to some point and intersecting some region but not within the other one, +* C++11 conformant: move semantics, stateful allocators, +* capable to store __value__ type with no default constructor. + +[heading Dependencies] + +R-tree depends on *Boost.Move*, *Boost.Container*, *Boost.Tuple*, *Boost.Utility*, *Boost.MPL*. + +[heading Contributors] + +The spatial index was originally started by Federico J. Fernandez during the Google Summer of Code 2008 program, mentored by Hartmut Kaiser. + +[heading Spatial thanks] + +I'd like to thank Barend Gehrels, Bruno Lalande, Mateusz Łoskot, Lucanus J. Simonson for their support and ideas. + +[endsect] + + diff --git a/doc/index/rtree/query.qbk b/doc/index/rtree/query.qbk new file mode 100644 index 000000000..328dc6437 --- /dev/null +++ b/doc/index/rtree/query.qbk @@ -0,0 +1,219 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2013 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section Queries] + +Queries returns `__value__`s which meets some predicates. Currently supported are three types of predicates: + +* spatial predicates - spatial conditions that must be met by stored Value and some Geometry, +* distance predicates - distance conditions that must be met by stored Value and some Geometry, +* user-defined unary predicate - function, function object or lambda expression checking user-defined condition. + +For example queries may be used to retrieve Values: + +* intersecting some area but not within other area, +* are nearest to some point, +* overlapping a box and has user-defined property. + +[section Performing a query] + +There are three ways to perform a query presented below. All of them returns `__value__`s intersecting some +region defined as a `__box__`. + +Method call + + std::vector<__value__> returned_values; + __box__ box_region(...); + rt.query(bgi::intersects(box_region), std::back_inserter(returned_values)); + +Function call + + std::vector<__value__> returned_values; + __box__ box_region(...); + index::query(rt, bgi::intersects(box_region), std::back_inserter(returned_values)); + +Use of pipe operator generating a range + + __box__ box_region(...); + BOOST_FOREACH(__value__ & v, rt | index::adaptors::queried(bgi::intersects(box_region))) + ; // do something with v + +[endsect] + +[section Spatial predicates] + +Queries using spatial predicates returns `__value__`s which are related somehow to some Geometry - box, polygon, etc. +Names of spatial predicates correspond to names of __boost_geometry__ algorithms. Examples of some +basic queries may be found in tables below. The query region and result `Value`s are orange. + +[table +[[intersects(Box)] [covered_by(Box)] [disjoint(Box)] [overlaps(Box)] [within(Box)]] +[[[$img/index/rtree/intersects.png]] [[$img/index/rtree/within.png]] [[$img/index/rtree/disjoint.png]] [[$img/index/rtree/overlaps.png]] [[$img/index/rtree/within.png]]] +] + +[table +[[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)]] +[[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]]] +] + +To use a spatial predicate one may use one of the functions defined in `boost::geometry::index` namespace. + + rt.query(index::intersects(box), std::back_inserter(result)); + rt.query(index::covered_by(box), std::back_inserter(result)); + rt.query(index::disjont(box), std::back_inserter(result)); + rt.query(index::overlaps(box), std::back_inserter(result)); + rt.query(index::within(box), std::back_inserter(result)); + +All spatial predicates may be negated, e.g.: + + rt.query(!index::intersects(box), std::back_inserter(result)); + // the same as + rt.query(index::disjoint(box), std::back_inserter(result)); + +[endsect] + +[section Distance predicates] + +[heading Nearest neighbours queries] + +Nearest neighbours queries returns `__value__`s which are closest to some point in space. +Additionally it is possible to define how the distance to the `Value` should be calculated. +The example of knn query is presented below. 5 `__value__`s nearest to some point are orange. + +[$img/index/rtree/knn.png] + +[heading k nearest neighbours] + +There are three ways of performing knn queries. Following queries returns +`k` `__value__`s closest to some point in space. For `__box__`es +`__indexable__`s the distance to the nearest point is calculated by default. + +Method call + + std::vector<__value__> returned_values; + __point__ pt(...); + rt.query(index::nearest(pt, k), std::back_inserter(returned_values)); + +Function call + + std::vector<__value__> returned_values; + __point__ pt(...); + index::query(rt, index::nearest(pt, k), std::back_inserter(returned_values)); + +Use of `operator |` + + __point__ pt(...); + BOOST_FOREACH(__value__ & v, rt | index::adaptors::queried(index::nearest(pt, k))) + ; // do something with v + +[endsect] + +[section User-defined unary predicate] + +The user may pass a `UnaryPredicate` - function, function object or lambda expression taking const reference to Value and returning bool. +This object may be passed to the query in order to check if `__value__` should be returned by the query. To do it one +may use `index::satisfies()` function like on the example below: + + bool is_red(__value__ const& v) + { + return v.is_red(); + } + + struct is_red_o + { + template + bool operator()(__value__ const& v) + { + return v.is_red(); + } + } + + // ... + + rt.query(index::intersects(box) && index::satisfies(is_red), + std::back_inserter(result)); + + rt.query(index::intersects(box) && index::satisfies(is_red_o()), + std::back_inserter(result)); + + #ifndef BOOST_NO_CXX11_LAMBDAS + rt.query(index::intersects(box) && index::satisfies([](__value__ const& v) { return v.is_red(); }), + std::back_inserter(result)); + #endif + +`satisfies()` may be negated, e.g.: + + bool is_red(__value__ const& v) { return v.is_red(); } + bool is_not_red(__value__ const& v) { return !v.is_red(); } + + // ... + + rt.query(index::intersects(box) && index::satisfies(is_red), + std::back_inserter(result)); + // the same as + rt.query(index::intersects(box) && !index::satisfies(is_not_red), + std::back_inserter(result)); + +[endsect] + +[section Passing a set of predicates] + +It's possible to use some number of predicates in one query by connecting them with `operator&&` e.g. `Pred1 && Pred2 && Pred3 && ...`. + +These predicates are connected by logical AND. Passing all predicates together not only makes possible +to construct advanced queries but is also faster than separate calls because the tree is traversed only once. +Traversing is continued and `Value`s are returned only if all predicates are met. Predicates are checked +left-to-right so placing most restictive predicates first should accelerate the search. + + rt.query(index::intersects(box1) && !index::within(box2), + std::back_inserter(result)); + + rt.query(index::intersects(box1) && !index::within(box2) && index::overlaps(box3), + std::back_inserter(result)); + +Of course it's possible to connect different types of predicates together. + + index::query(rt, index::nearest(pt, k) && index::within(b), std::back_inserter(returned_values)); + + BOOST_FOREACH(Value & v, rt | index::adaptors::queried(index::nearest(pt, k) && index::covered_by(b))) + ; // do something with v + +[endsect] + +[section Inserting query results into the other R-tree] + +There are several ways of inserting Values returned by a query to the other R-tree container. +The most basic way is creating a temporary container for Values and insert them later. + + namespace bgi = boost::geometry::index; + typedef std::pair __value__; + typedef bgi::rtree< __value__, bgi::linear<32, 8> > RTree; + + RTree rt1; + /* some inserting into the tree */ + + std::vector result; + rt1.query(bgi::intersects(Box(/*...*/)), std::back_inserter(result)); + RTree rt2(result.begin(), result.end()); + +However there are better ways. One of these methods is mentioned in the "Creation and modification" section. +The insert iterator may be passed directly into the query. + + RTree rt3; + rt1.query(bgi::intersects(Box(/*...*/))), bgi::inserter(rt3)); + +If you like Boost.Range you'll appreciate the third option. You may pass the result Range directly into the +constructor. + + RTree rt4(rt1 | bgi::adaptors::queried(bgi::intersects(Box(/*...*/))))); + +[endsect] + +[endsect] [/ Queries /] diff --git a/doc/index/rtree/quickstart.qbk b/doc/index/rtree/quickstart.qbk new file mode 100644 index 000000000..92c50c4fc --- /dev/null +++ b/doc/index/rtree/quickstart.qbk @@ -0,0 +1,59 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2012 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section:rtree_quickstart Quick Start] + +This Quick Start section shows simple way to creating a typical R-tree and perform +spatial query. + +The code below assumes that following files are included and namespaces used. + +[rtree_quickstart_include] + +Typically you'll store e.g. `std::pair` in the __rtree__. `MyGeometryId` +will be some indentifier of a complex `Geometry` stored in other container, e.g. index type +of a `Polygon` stored in the vector or an iterator of list of `Ring`s. To keep it simple to +define `Value` we will use predefined __box__ and unsigned int. + +[rtree_quickstart_valuetype] + +R-tree may be created using various algorithm and parameters. You should choose the algorithm you'll +find the best for your purpose. In this example we will use quadratic algorithm. Parameters are +passed as template parameters. Maximum number of elements in nodes is set to 16. + +[rtree_quickstart_create] + +Typically `Value`s will be generated in a loop from e.g. `Polygon`s stored in some other container. +In this case `Box` objects will probably be created with `geometry::envelope()` function. +But to keep it simple lets just generate some boxes manually and insert them into the R-tree by +using `insert()` method. + +[rtree_quickstart_insert] + +There are various types of spatial queries that may be performed, they can be even combined together +in one call. For simplicity, we use the default one. The following query return values intersecting +a box. The sequence of `Values` in the result is not specified. + +[rtree_quickstart_spatial_query] + +Other type of query is k-nearest neighbor search. It returns some number of values nearest to some point +in space. The default knn query may be performed as follows. The sequence of `Values` in the result is not specified. + +[rtree_quickstart_nearest_query] + +At the end we'll print results. + +[rtree_quickstart_output] + +[h3 More] +More information about the R-tree implementation, other algorithms and queries may be found in +other parts of this documentation. + +[endsect] diff --git a/doc/index/rtree/reference.qbk b/doc/index/rtree/reference.qbk new file mode 100644 index 000000000..c53b01fbd --- /dev/null +++ b/doc/index/rtree/reference.qbk @@ -0,0 +1,40 @@ +[/============================================================================ + Boost.Geometry Index + + Copyright (c) 2011-2013 Adam Wulkiewicz. + + Use, modification and distribution is subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================/] + +[section:reference Reference] + +[include ../generated/rtree.qbk] +[include ../generated/rtree_functions.qbk] + +[section:parameters R-tree parameters (boost::geometry::index::)] + +[include ../generated/rtree_linear.qbk] +[include ../generated/rtree_quadratic.qbk] +[include ../generated/rtree_rstar.qbk] +[include ../generated/rtree_dynamic_linear.qbk] +[include ../generated/rtree_dynamic_quadratic.qbk] +[include ../generated/rtree_dynamic_rstar.qbk] + +[endsect] + +[/section:function_objects Function objects (boost::geometry::index::)/] + +[include ../generated/indexable.qbk] +[include ../generated/equal_to.qbk] + +[/endsect/] + +[include ../generated/predicates.qbk] +[include ../generated/nearest_relations.qbk] +[include ../generated/adaptors.qbk] + +[include ../generated/inserters.qbk] + +[endsect] diff --git a/doc/index/src/examples/Jamfile.v2 b/doc/index/src/examples/Jamfile.v2 new file mode 100644 index 000000000..e221ca86b --- /dev/null +++ b/doc/index/src/examples/Jamfile.v2 @@ -0,0 +1,19 @@ +# Boost.Geometry Index +# +# Copyright (c) 2011-2012 Adam Wulkiewicz, Lodz, Poland. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import testing ; + +project boost-geometry-index-doc-src-examples + : + requirements + ../../.. + #../../../boost/geometry/extensions/contrib/ttmath + msvc:on + ; + +build-project rtree ; diff --git a/doc/index/src/examples/rtree/Jamfile.v2 b/doc/index/src/examples/rtree/Jamfile.v2 new file mode 100644 index 000000000..79778b9ab --- /dev/null +++ b/doc/index/src/examples/rtree/Jamfile.v2 @@ -0,0 +1,25 @@ +# Boost.Geometry Index +# +# Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +exe quick_start : quick_start.cpp ; +exe polygons_vector : polygons_vector.cpp ; +exe polygons_shared_ptr : polygons_shared_ptr.cpp ; +exe variants_map : variants_map.cpp ; +exe value_shared_ptr : value_shared_ptr.cpp ; +exe value_index : value_index.cpp ; + +exe interprocess : interprocess.cpp /boost/thread//boost_thread + : + acc:-lrt + acc-pa_risc:-lrt + gcc-mingw:"-lole32 -loleaut32 -lpsapi -ladvapi32" + hpux,gcc:"-Wl,+as,mpas" + : + multi + : # requirements + ; diff --git a/doc/index/src/examples/rtree/interprocess.cpp b/doc/index/src/examples/rtree/interprocess.cpp new file mode 100644 index 000000000..61d3f0b50 --- /dev/null +++ b/doc/index/src/examples/rtree/interprocess.cpp @@ -0,0 +1,112 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_interprocess + +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include //std::system + +//For parent process argc == 1, for child process argc > 1 +int main(int argc, char *argv[]) +{ + using namespace boost::interprocess; + namespace bg = boost::geometry; + namespace bgm = bg::model; + namespace bgi = bg::index; + + typedef bgm::point P; + typedef bgm::box

    B; + + typedef bgi::linear<32, 8> Par; + typedef bgi::indexable I; + typedef bgi::equal_to E; + typedef allocator Alloc; + typedef bgi::rtree Rtree; + + //Parent process + if ( argc == 1 ) + { + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + managed_shared_memory segment(create_only, "MySharedMemory", 65536); + + std::cout << "Parent: Constructing container\n"; + + Rtree * tree = segment.construct("Rtree")(Par(), I(), E(), Alloc(segment.get_segment_manager())); + + std::cout << "Parent: Filling container with 100 boxes\n"; + + for ( float i = 0 ; i < 100 ; i += 1 ) + tree->insert(B(P(i, i), P(i+0.5f, i+0.5f))); + + std::cout << "Parent: Tree content\n"; + Rtree::bounds_type bb = tree->bounds(); + std::cout << "[(" << bg::get<0>(bb.min_corner()) << ", " << bg::get<1>(bb.min_corner()) + << ")(" << bg::get<0>(bb.max_corner()) << ", " << bg::get<1>(bb.max_corner()) << ")]\n"; + + std::cout << "Parent: Running child process\n"; + + std::string s(argv[0]); s += " child "; + if ( 0 != std::system(s.c_str()) ) + return 1; + + if ( segment.find("Rtree").first ) + return 1; + + std::cout << "Parent: Container was properly destroyed by the child process\n"; + } + //Child process + else + { + managed_shared_memory segment(open_only, "MySharedMemory"); + + std::cout << "Child: Searching of the container in shared memory\n"; + + Rtree * tree = segment.find("Rtree").first; + + std::cout << "Child: Querying for objects intersecting box = [(45, 45)(55, 55)]\n"; + + std::vector result; + unsigned k = tree->query(bgi::intersects(B(P(45, 45), P(55, 55))), std::back_inserter(result)); + + std::cout << "Child: Found objects:\n"; + std::cout << k << "\n"; + BOOST_FOREACH(B const& b, result) + { + std::cout << "[(" << bg::get<0>(b.min_corner()) << ", " << bg::get<1>(b.min_corner()) + << ")(" << bg::get<0>(b.max_corner()) << ", " << bg::get<1>(b.max_corner()) << ")]\n"; + } + std::cout << "\n"; + + std::cout << "Child: Destroying container\n"; + + segment.destroy("Rtree"); + } + + return 0; +}; + +//] diff --git a/doc/index/src/examples/rtree/polygons_shared_ptr.cpp b/doc/index/src/examples/rtree/polygons_shared_ptr.cpp new file mode 100644 index 000000000..c65ba5376 --- /dev/null +++ b/doc/index/src/examples/rtree/polygons_shared_ptr.cpp @@ -0,0 +1,88 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_polygons_shared_ptr + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +int main(void) +{ + typedef bg::model::point point; + typedef bg::model::box box; + typedef bg::model::polygon polygon; // ccw, open polygon + typedef boost::shared_ptr shp; + typedef std::pair value; + + // create the rtree using default constructor + bgi::rtree< value, bgi::linear<16, 4> > rtree; + + std::cout << "filling index with polygons shared pointers:" << std::endl; + + // create some polygons and fill the spatial index + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + // create a polygon + shp p(new polygon()); + for ( float a = 0 ; a < 6.28316f ; a += 1.04720f ) + { + float x = i + int(10*::cos(a))*0.1f; + float y = i + int(10*::sin(a))*0.1f; + p->outer().push_back(point(x, y)); + } + + // display new polygon + std::cout << bg::wkt(*p) << std::endl; + + // calculate polygon bounding box + box b = bg::return_envelope(*p); + // insert new value + rtree.insert(std::make_pair(b, p)); + } + + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value const& v, result_s) + std::cout << bg::wkt(*v.second) << std::endl; + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value const& v, result_n) + std::cout << bg::wkt(*v.second) << std::endl; + + return 0; +} + +//] diff --git a/doc/index/src/examples/rtree/polygons_vector.cpp b/doc/index/src/examples/rtree/polygons_vector.cpp new file mode 100644 index 000000000..a8984a732 --- /dev/null +++ b/doc/index/src/examples/rtree/polygons_vector.cpp @@ -0,0 +1,96 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_polygons_vector + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +int main(void) +{ + typedef bg::model::point point; + typedef bg::model::box box; + typedef bg::model::polygon polygon; // ccw, open polygon + typedef std::pair value; + + // polygons + std::vector polygons; + + // create some polygons + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + // create a polygon + polygon p; + for ( float a = 0 ; a < 6.28316f ; a += 1.04720f ) + { + float x = i + int(10*::cos(a))*0.1f; + float y = i + int(10*::sin(a))*0.1f; + p.outer().push_back(point(x, y)); + } + + // add polygon + polygons.push_back(p); + } + + // display polygons + std::cout << "generated polygons:" << std::endl; + BOOST_FOREACH(polygon const& p, polygons) + std::cout << bg::wkt(p) << std::endl; + + // create the rtree using default constructor + bgi::rtree< value, bgi::rstar<16, 4> > rtree; + + // fill the spatial index + for ( unsigned i = 0 ; i < polygons.size() ; ++i ) + { + // calculate polygon bounding box + box b = bg::return_envelope(polygons[i]); + // insert new value + rtree.insert(std::make_pair(b, i)); + } + + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value const& v, result_s) + std::cout << bg::wkt(polygons[v.second]) << std::endl; + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value const& v, result_n) + std::cout << bg::wkt(polygons[v.second]) << std::endl; + + return 0; +} + +//] diff --git a/doc/index/src/examples/rtree/quick_start.cpp b/doc/index/src/examples/rtree/quick_start.cpp new file mode 100644 index 000000000..80c883122 --- /dev/null +++ b/doc/index/src/examples/rtree/quick_start.cpp @@ -0,0 +1,87 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_quickstart + +//[rtree_quickstart_include + +#include +#include +#include + +#include + +// to store queries results +#include + +// just for output +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; +//] + +int main(void) +{ + //[rtree_quickstart_valuetype + typedef bg::model::point point; + typedef bg::model::box box; + typedef std::pair value; + //] + + //[rtree_quickstart_create + // create the rtree using default constructor + bgi::rtree< value, bgi::quadratic<16> > rtree; + //] + + //[rtree_quickstart_insert + // create some values + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + // create a box + box b(point(i, i), point(i + 0.5f, i + 0.5f)); + // insert new value + rtree.insert(std::make_pair(b, i)); + } + //] + + //[rtree_quickstart_spatial_query + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + //] + + //[rtree_quickstart_nearest_query + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + //] + + //[rtree_quickstart_output + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value const& v, result_s) + std::cout << bg::wkt(v.first) << " - " << v.second << std::endl; + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value const& v, result_n) + std::cout << bg::wkt(v.first) << " - " << v.second << std::endl; + //] + + return 0; +} + +//] diff --git a/doc/index/src/examples/rtree/value_index.cpp b/doc/index/src/examples/rtree/value_index.cpp new file mode 100644 index 000000000..32f306909 --- /dev/null +++ b/doc/index/src/examples/rtree/value_index.cpp @@ -0,0 +1,97 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_value_index + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +template +class my_indexable +{ + typedef typename Container::size_type size_t; + typedef typename Container::const_reference cref; + Container const& container; + +public: + typedef cref result_type; + explicit my_indexable(Container const& c) : container(c) {} + result_type operator()(size_t i) const { return container[i]; } +}; + +int main(void) +{ + typedef bg::model::point point; + typedef bg::model::box box; + typedef std::vector::size_type value; + typedef bgi::rstar<16, 4> parameters; + typedef my_indexable< std::vector > indexable_getter; + + // boxes + std::vector boxes; + + // create some boxes + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + // add a box + boxes.push_back(box(point(i, i), point(i+0.5f, i+0.5f))); + } + + // display boxes + std::cout << "generated boxes:" << std::endl; + BOOST_FOREACH(box const& b, boxes) + std::cout << bg::wkt(b) << std::endl; + + // create the rtree + parameters params; + indexable_getter ind(boxes); + bgi::rtree rtree(params, ind); + + // fill the spatial index + for ( size_t i = 0 ; i < boxes.size() ; ++i ) + rtree.insert(i); + + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value i, result_s) + std::cout << bg::wkt(boxes[i]) << std::endl; + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value i, result_n) + std::cout << bg::wkt(boxes[i]) << std::endl; + + return 0; +} + +//] diff --git a/doc/index/src/examples/rtree/value_shared_ptr.cpp b/doc/index/src/examples/rtree/value_shared_ptr.cpp new file mode 100644 index 000000000..e2ff55737 --- /dev/null +++ b/doc/index/src/examples/rtree/value_shared_ptr.cpp @@ -0,0 +1,91 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_value_shared_ptr + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +namespace boost { namespace geometry { namespace index { + +template +struct indexable< boost::shared_ptr > +{ + typedef boost::shared_ptr V; + + typedef Box const& result_type; + result_type operator()(V const& v) const { return *v; } +}; + +}}} // namespace boost::geometry::index + +int main(void) +{ + typedef bg::model::point point; + typedef bg::model::box box; + typedef boost::shared_ptr shp; + typedef shp value; + + // create the rtree using default constructor + bgi::rtree< value, bgi::linear<16, 4> > rtree; + + std::cout << "filling index with boxes shared pointers:" << std::endl; + + // fill the spatial index + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + // create a box + shp b(new box(point(i, i), point(i+0.5f, i+0.5f))); + + // display new box + std::cout << bg::wkt(*b) << std::endl; + + // insert new value + rtree.insert(b); + } + + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value const& v, result_s) + std::cout << bg::wkt(*v) << std::endl; + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value const& v, result_n) + std::cout << bg::wkt(*v) << std::endl; + + return 0; +} + +//] diff --git a/doc/index/src/examples/rtree/variants_map.cpp b/doc/index/src/examples/rtree/variants_map.cpp new file mode 100644 index 000000000..462795002 --- /dev/null +++ b/doc/index/src/examples/rtree/variants_map.cpp @@ -0,0 +1,143 @@ +// Boost.Geometry Index +// +// Quickbook Examples +// +// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +//[rtree_variants_map + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +typedef bg::model::point point; +typedef bg::model::box box; +typedef bg::model::polygon polygon; // ccw, open polygon +typedef bg::model::ring ring; // ccw, open ring +typedef bg::model::linestring linestring; +typedef boost::variant geometry; + +typedef std::map map; +typedef std::pair value; + +template +void fill(unsigned i, Container & container) +{ + for ( float a = 0 ; a < 6.28316f ; a += 1.04720f ) + { + float x = i + int(10*::cos(a))*0.1f; + float y = i + int(10*::sin(a))*0.1f; + container.push_back(point(x, y)); + } +} + +struct print_visitor : public boost::static_visitor<> +{ + void operator()(polygon const& g) const { std::cout << bg::wkt(g) << std::endl; } + void operator()(ring const& g) const { std::cout << bg::wkt(g) << std::endl; } + void operator()(linestring const& g) const { std::cout << bg::wkt(g) << std::endl; } +}; + +struct envelope_visitor : public boost::static_visitor +{ + box operator()(polygon const& g) const { return bg::return_envelope(g); } + box operator()(ring const& g) const { return bg::return_envelope(g); } + box operator()(linestring const& g) const { return bg::return_envelope(g); } +}; + + +int main(void) +{ + // geometries container + map geometries; + + // create some geometries + for ( unsigned i = 0 ; i < 10 ; ++i ) + { + unsigned c = rand() % 3; + + if ( 0 == c ) + { + // create polygon + polygon p; + fill(i, p.outer()); + geometries.insert(std::make_pair(i, geometry(p))); + } + else if ( 1 == c ) + { + // create ring + ring r; + fill(i, r); + geometries.insert(std::make_pair(i, geometry(r))); + } + else if ( 2 == c ) + { + // create linestring + linestring l; + fill(i, l); + geometries.insert(std::make_pair(i, geometry(l))); + } + } + + // display geometries + std::cout << "generated geometries:" << std::endl; + BOOST_FOREACH(map::value_type const& p, geometries) + boost::apply_visitor(print_visitor(), p.second); + + // create the rtree using default constructor + bgi::rtree< value, bgi::quadratic<16, 4> > rtree; + + // fill the spatial index + for ( map::iterator it = geometries.begin() ; it != geometries.end() ; ++it ) + { + // calculate polygon bounding box + box b = boost::apply_visitor(envelope_visitor(), it->second); + // insert new value + rtree.insert(std::make_pair(b, it)); + } + + // find values intersecting some area defined by a box + box query_box(point(0, 0), point(5, 5)); + std::vector result_s; + rtree.query(bgi::intersects(query_box), std::back_inserter(result_s)); + + // find 5 nearest values to a point + std::vector result_n; + rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n)); + + // display results + std::cout << "spatial query box:" << std::endl; + std::cout << bg::wkt(query_box) << std::endl; + std::cout << "spatial query result:" << std::endl; + BOOST_FOREACH(value const& v, result_s) + boost::apply_visitor(print_visitor(), v.second->second); + + std::cout << "knn query point:" << std::endl; + std::cout << bg::wkt(point(0, 0)) << std::endl; + std::cout << "knn query result:" << std::endl; + BOOST_FOREACH(value const& v, result_n) + boost::apply_visitor(print_visitor(), v.second->second); + + return 0; +} + +//] diff --git a/doc/make_qbk.py b/doc/make_qbk.py index 74aa52995..1a01bf2b9 100755 --- a/doc/make_qbk.py +++ b/doc/make_qbk.py @@ -148,4 +148,9 @@ group_to_quickbook("arithmetic") group_to_quickbook("register") group_to_quickbook("enum") -os.system("../../../b2") +os.chdir("index") +execfile("make_qbk.py") +os.chdir("..") + +# Use either bjam or b2 or ../../../b2 (the last should be done on Release branch) +os.system("bjam") diff --git a/doc/quickref.xml b/doc/quickref.xml index 2a70b4612..98c9ef203 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -8,6 +8,7 @@ Copyright (c) 2009-2011 Mateusz Loskot, London, UK. Copyright (c) 2009-2011 Barend Gehrels, Amsterdam, the Netherlands. Copyright (c) 2009-2011 Bruno Lalande, Paris, France. + Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -624,5 +625,128 @@ + + + + + + + + + + Spatial indexes + + + + + + + R-tree + + boost::geometry::index::rtree + + R-tree parameters + + boost::geometry::index::linear + boost::geometry::index::quadratic + boost::geometry::index::rstar + boost::geometry::index::dynamic_linear + boost::geometry::index::dynamic_quadratic + boost::geometry::index::dynamic_rstar + + R-tree constructors and destructor + + rtree() + rtree(parameters_type const &, indexable_getter const &, value_equal const &, allocator_type const &) + rtree(Iterator, Iterator) + rtree(Range const &) + rtree(rtree const &) + rtree(rtree const &, allocator_type const &) + rtree(rtree &&) + rtree(rtree &&, allocator_type const &) + ~rtree() + + + + R-tree member functions + + operator=(const rtree &) + operator=(rtree &&) + swap(rtree &) + insert(value_type const &) + insert(Iterator, Iterator) + insert(Range const &) + remove(value_type const &) + remove(Iterator, Iterator) + remove(Range const &) + query(Predicates const &, OutIter) + size() + empty() + clear() + bounds() + count(ValueOrIndexable const &) + parameters() + indexable_get() + value_eq() + get_allocator() + + + + R-tree free functions (boost::geometry::index::) + + insert(rtree<...> &, Value const &) + insert(rtree<...> &, Iterator, Iterator) + insert(rtree<...> &, Range const &) + remove(rtree<...> &, Value const &) + remove(rtree<...> &, Iterator, Iterator) + remove(rtree<...> &, Range const &) + query(rtree<...> const &, Predicates const &, OutIter) + clear(rtree<...> &) + size(rtree<...> const &) + empty(rtree<...> const &) + bounds(rtree<...> const &) + swap(rtree<...> &, rtree<...> &) + + + + + + Observers (boost::geometry::index::) + + boost::geometry::index::indexable + boost::geometry::index::equal_to + + Inserters (boost::geometry::index::) + + inserter(Container &) + + Adaptors (boost::geometry::index::adaptors::) + + queried(Predicates const &) + + + + Predicates (boost::geometry::index::) + + covered_by(Geometry const &) + disjoint(Geometry const &) + intersects(Geometry const &) + overlaps(Geometry const &) + within(Geometry const &) + satisfies(UnaryPredicate const &) + nearest(Point const &, unsigned) + + + + + + diff --git a/doc/readme.txt b/doc/readme.txt index f1d17d152..3d04faf18 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -15,9 +15,10 @@ and that it translates from Doxygen-XML output to Quickbook (without xslt) 1) install Doxygen 2) install QuickBook using http://www.boost.org/doc/libs/1_45_0/doc/html/quickbook/install.html#quickbook.install.linux -3) compile doxygen_xml2qbk, in src/docutils/tools/doxygen_xml2qbk -4) put binary somewhere, e.g. in /usr/local/bin/doxygen_xml2qbk -5) execute python file "make_qbk.py" (calling doxygen, doxygen_xml2qbk, bjam) +3) unpack RapidXML, see src/docutils/tools/doxygen_xml2qbk/contrib/readme.txt +4) compile doxygen_xml2qbk, in src/docutils/tools/doxygen_xml2qbk +5) put binary somewhere, e.g. in /usr/local/bin/doxygen_xml2qbk +6) execute python file "make_qbk.py" (calling doxygen, doxygen_xml2qbk, bjam) Folders in this folder: concept: manually written documentation QBK files, on concept diff --git a/doc/reference.qbk b/doc/reference.qbk index a9a2192b9..563f589ef 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -4,6 +4,7 @@ Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands. Copyright (c) 2009-2012 Mateusz Loskot, London, UK. Copyright (c) 2009-2012 Bruno Lalande, Paris, France. + Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -241,6 +242,34 @@ [endsect] +[section:spatial_indexes Spatial indexes] + +[section:rtree R-tree] +[include index/generated/rtree.qbk] +[include index/generated/rtree_functions.qbk] +[section:parameters R-tree parameters (boost::geometry::index::)] +[include index/generated/rtree_linear.qbk] +[include index/generated/rtree_quadratic.qbk] +[include index/generated/rtree_rstar.qbk] +[include index/generated/rtree_dynamic_linear.qbk] +[include index/generated/rtree_dynamic_quadratic.qbk] +[include index/generated/rtree_dynamic_rstar.qbk] +[endsect] +[endsect] + +[section:observers Observers (boost::geometry::index::)] +[include index/generated/indexable.qbk] +[include index/generated/equal_to.qbk] +[endsect] +[include index/generated/inserters.qbk] +[include index/generated/adaptors.qbk] + +[include index/generated/predicates.qbk] +[/include index/generated/nearest_relations.qbk] + +[endsect] + + [section:strategies Strategies] [include generated/distance_pythagoras.qbk] [include generated/distance_haversine.qbk] diff --git a/doc/reference/core/max_corner.qbk b/doc/reference/core/max_corner.qbk index e3d69aaa0..1d56590ec 100644 --- a/doc/reference/core/max_corner.qbk +++ b/doc/reference/core/max_corner.qbk @@ -19,8 +19,8 @@ Indicates the maximal corner (upper right) of a box to be get, set or processed [heading See also] * [link geometry.reference.constants.min_corner min_corner] -* [link geometry.reference.access.get.get_2_with_index get with index] -* [link geometry.reference.access.set.set_3_with_index set with index] +* [link geometry.reference.access.get.get_1_with_index get with index] +* [link geometry.reference.access.set.set_2_with_index set with index] [endsect] diff --git a/doc/reference/core/min_corner.qbk b/doc/reference/core/min_corner.qbk index 061412bd9..a169b0475 100644 --- a/doc/reference/core/min_corner.qbk +++ b/doc/reference/core/min_corner.qbk @@ -19,7 +19,7 @@ Indicates the minimal corner (lower left) of a box to be get, set or processed [heading See also] * [link geometry.reference.constants.max_corner max_corner] -* [link geometry.reference.access.get.get_2_with_index get with index] -* [link geometry.reference.access.set.set_3_with_index set with index] +* [link geometry.reference.access.get.get_1_with_index get with index] +* [link geometry.reference.access.set.set_2_with_index set with index] [endsect] diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 1bb40e2bc..879ca5fde 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -1,9 +1,10 @@ [/============================================================================ Boost.Geometry (aka GGL, Generic Geometry Library) - Copyright (c) 2009-2012 Barend Gehrels, Geodan, Amsterdam, the Netherlands. - Copyright (c) 2009-2012 Mateusz Loskot (mateusz@loskot.net) - Copyright (c) 2009-2012 Mateusz Lalande, Paris, France. + Copyright (c) 2009-2013 Barend Gehrels, Geodan, Amsterdam, the Netherlands. + Copyright (c) 2009-2013 Mateusz Loskot (mateusz@loskot.net) + Copyright (c) 2009-2013 Mateusz Lalande, Paris, France. + Copyright (c) 2011-2013 Adam Wulkiewicz Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -12,6 +13,27 @@ [section:release_notes Release Notes] +[/=================] +[heading Boost 1.54] +[/=================] + +[*Additional functionality] + +* added Spatial Index, developed for Boost.Geometry by Adam Wulkiewicz. The spatial index was originally started by Federico J. Fernandez during the Google Summer of Code 2008 program, mentored by Hartmut Kaiser. + +[*Bugfixes] +* collinear opposite segments did sometimes (in circles) have a robustness issue, fixed + +[*Solved tickets] + +* [@https://svn.boost.org/trac/boost/ticket/7462 7462] degenerate union result for float, fixed +* [@https://svn.boost.org/trac/boost/ticket/7465 7465] wrong construtors access type in scale_transformer class, fixed +* [@https://svn.boost.org/trac/boost/ticket/7802 7802] cart_intersect.hpp unused parameter warnings, fixed +* [@https://svn.boost.org/trac/boost/ticket/8254 8254] faulty intersection, fixed +* [@https://svn.boost.org/trac/boost/ticket/8393 8393] polygon model doesn't adhere to stated Polygon concept rules, doc updated. +* [@https://svn.boost.org/trac/boost/ticket/8403 8403] silenced compiler warning C4127: conditional expression is constant +* [@https://svn.boost.org/trac/boost/ticket/8405 8405] silenced compiler warning C4189: '...' : local variable is initialized but not referenced + [/=================] [heading Boost 1.53] diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/configuration.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/configuration.hpp index 96cf8104c..3cb8ddf83 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/configuration.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/configuration.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -14,6 +15,7 @@ #include + struct configuration { // To transfer e.g. c:/_svn/boost/trunk/boost/geometry/algorithms/area.hpp @@ -27,6 +29,10 @@ struct configuration std::vector convenience_headers; std::string skip_namespace; + + enum output_style_type {def, alt}; + output_style_type output_style; + configuration() : output_style(def) {} }; diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/license.txt b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/license.txt new file mode 100644 index 000000000..140983180 --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/license.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/manual.html b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/manual.html new file mode 100644 index 000000000..2c422703f --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/manual.html @@ -0,0 +1,406 @@ +

    RAPIDXML Manual

    Version 1.13

    Copyright (C) 2006, 2009 Marcin Kalicinski
    See accompanying file license.txt for license information.

    Table of Contents

    1. What is RapidXml?
    1.1 Dependencies And Compatibility
    1.2 Character Types And Encodings
    1.3 Error Handling
    1.4 Memory Allocation
    1.5 W3C Compliance
    1.6 API Design
    1.7 Reliability
    1.8 Acknowledgements
    2. Two Minute Tutorial
    2.1 Parsing
    2.2 Accessing The DOM Tree
    2.3 Modifying The DOM Tree
    2.4 Printing XML
    3. Differences From Regular XML Parsers
    3.1 Lifetime Of Source Text
    3.2 Ownership Of Strings
    3.3 Destructive Vs Non-Destructive Mode
    4. Performance
    4.1 Comparison With Other Parsers
    5. Reference

    1. What is RapidXml?

    RapidXml is an attempt to create the fastest XML DOM parser possible, while retaining useability, portability and reasonable W3C compatibility. It is an in-situ parser written in C++, with parsing speed approaching that of strlen() function executed on the same data.

    + Entire parser is contained in a single header file, so no building or linking is neccesary. To use it you just need to copy rapidxml.hpp file to a convenient place (such as your project directory), and include it where needed. You may also want to use printing functions contained in header rapidxml_print.hpp.

    1.1 Dependencies And Compatibility

    RapidXml has no dependencies other than a very small subset of standard C++ library (<cassert>, <cstdlib>, <new> and <exception>, unless exceptions are disabled). It should compile on any reasonably conformant compiler, and was tested on Visual C++ 2003, Visual C++ 2005, Visual C++ 2008, gcc 3, gcc 4, and Comeau 4.3.3. Care was taken that no warnings are produced on these compilers, even with highest warning levels enabled.

    1.2 Character Types And Encodings

    RapidXml is character type agnostic, and can work both with narrow and wide characters. Current version does not fully support UTF-16 or UTF-32, so use of wide characters is somewhat incapacitated. However, it should succesfully parse wchar_t strings containing UTF-16 or UTF-32 if endianness of the data matches that of the machine. UTF-8 is fully supported, including all numeric character references, which are expanded into appropriate UTF-8 byte sequences (unless you enable parse_no_utf8 flag).

    + Note that RapidXml performs no decoding - strings returned by name() and value() functions will contain text encoded using the same encoding as source file. Rapidxml understands and expands the following character references: &apos; &amp; &quot; &lt; &gt; &#...; Other character references are not expanded.

    1.3 Error Handling

    By default, RapidXml uses C++ exceptions to report errors. If this behaviour is undesirable, RAPIDXML_NO_EXCEPTIONS can be defined to suppress exception code. See parse_error class and parse_error_handler() function for more information.

    1.4 Memory Allocation

    RapidXml uses a special memory pool object to allocate nodes and attributes, because direct allocation using new operator would be far too slow. Underlying memory allocations performed by the pool can be customized by use of memory_pool::set_allocator() function. See class memory_pool for more information.

    1.5 W3C Compliance

    RapidXml is not a W3C compliant parser, primarily because it ignores DOCTYPE declarations. There is a number of other, minor incompatibilities as well. Still, it can successfully parse and produce complete trees of all valid XML files in W3C conformance suite (over 1000 files specially designed to find flaws in XML processors). In destructive mode it performs whitespace normalization and character entity substitution for a small set of built-in entities.

    1.6 API Design

    RapidXml API is minimalistic, to reduce code size as much as possible, and facilitate use in embedded environments. Additional convenience functions are provided in separate headers: rapidxml_utils.hpp and rapidxml_print.hpp. Contents of these headers is not an essential part of the library, and is currently not documented (otherwise than with comments in code).

    1.7 Reliability

    RapidXml is very robust and comes with a large harness of unit tests. Special care has been taken to ensure stability of the parser no matter what source text is thrown at it. One of the unit tests produces 100,000 randomly corrupted variants of XML document, which (when uncorrupted) contains all constructs recognized by RapidXml. RapidXml passes this test when it correctly recognizes that errors have been introduced, and does not crash or loop indefinitely.

    + Another unit test puts RapidXml head-to-head with another, well estabilished XML parser, and verifies that their outputs match across a wide variety of small and large documents.

    + Yet another test feeds RapidXml with over 1000 test files from W3C compliance suite, and verifies that correct results are obtained. There are also additional tests that verify each API function separately, and test that various parsing modes work as expected.

    1.8 Acknowledgements

    I would like to thank Arseny Kapoulkine for his work on pugixml, which was an inspiration for this project. Additional thanks go to Kristen Wegner for creating pugxml, from which pugixml was derived. Janusz Wohlfeil kindly ran RapidXml speed tests on hardware that I did not have access to, allowing me to expand performance comparison table.

    2. Two Minute Tutorial

    2.1 Parsing

    The following code causes RapidXml to parse a zero-terminated string named text:
    using namespace rapidxml;
    +xml_document<> doc;    // character type defaults to char
    +doc.parse<0>(text);    // 0 means default parse flags
    +
    doc object is now a root of DOM tree containing representation of the parsed XML. Because all RapidXml interface is contained inside namespace rapidxml, users must either bring contents of this namespace into scope, or fully qualify all the names. Class xml_document represents a root of the DOM hierarchy. By means of public inheritance, it is also an xml_node and a memory_pool. Template parameter of xml_document::parse() function is used to specify parsing flags, with which you can fine-tune behaviour of the parser. Note that flags must be a compile-time constant.

    2.2 Accessing The DOM Tree

    To access the DOM tree, use methods of xml_node and xml_attribute classes:
    cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
    +xml_node<> *node = doc.first_node("foobar");
    +cout << "Node foobar has value " << node->value() << "\n";
    +for (xml_attribute<> *attr = node->first_attribute();
    +     attr; attr = attr->next_attribute())
    +{
    +    cout << "Node foobar has attribute " << attr->name() << " ";
    +    cout << "with value " << attr->value() << "\n";
    +}
    +

    2.3 Modifying The DOM Tree

    DOM tree produced by the parser is fully modifiable. Nodes and attributes can be added/removed, and their contents changed. The below example creates a HTML document, whose sole contents is a link to google.com website:
    xml_document<> doc;
    +xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
    +doc.append_node(node);
    +xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
    +node->append_attribute(attr);
    +
    One quirk is that nodes and attributes do not own the text of their names and values. This is because normally they only store pointers to the source text. So, when assigning a new name or value to the node, care must be taken to ensure proper lifetime of the string. The easiest way to achieve it is to allocate the string from the xml_document memory pool. In the above example this is not necessary, because we are only assigning character constants. But the code below uses memory_pool::allocate_string() function to allocate node name (which will have the same lifetime as the document), and assigns it to a new node:
    xml_document<> doc;
    +char *node_name = doc.allocate_string(name);        // Allocate string and copy name into it
    +xml_node<> *node = doc.allocate_node(node_element, node_name);  // Set node name to node_name
    +
    Check Reference section for description of the entire interface.

    2.4 Printing XML

    You can print xml_document and xml_node objects into an XML string. Use print() function or operator <<, which are defined in rapidxml_print.hpp header.
    using namespace rapidxml;
    +xml_document<> doc;    // character type defaults to char
    +// ... some code to fill the document
    +
    +// Print to stream using operator <<
    +std::cout << doc;   
    +
    +// Print to stream using print function, specifying printing flags
    +print(std::cout, doc, 0);   // 0 means default printing flags
    +
    +// Print to string using output iterator
    +std::string s;
    +print(std::back_inserter(s), doc, 0);
    +
    +// Print to memory buffer using output iterator
    +char buffer[4096];                      // You are responsible for making the buffer large enough!
    +char *end = print(buffer, doc, 0);      // end contains pointer to character after last printed character
    +*end = 0;                               // Add string terminator after XML
    +

    3. Differences From Regular XML Parsers

    RapidXml is an in-situ parser, which allows it to achieve very high parsing speed. In-situ means that parser does not make copies of strings. Instead, it places pointers to the source text in the DOM hierarchy.

    3.1 Lifetime Of Source Text

    In-situ parsing requires that source text lives at least as long as the document object. If source text is destroyed, names and values of nodes in DOM tree will become destroyed as well. Additionally, whitespace processing, character entity translation, and zero-termination of strings require that source text be modified during parsing (but see non-destructive mode). This makes the text useless for further processing once it was parsed by RapidXml.

    + In many cases however, these are not serious issues.

    3.2 Ownership Of Strings

    Nodes and attributes produced by RapidXml do not own their name and value strings. They merely hold the pointers to them. This means you have to be careful when setting these values manually, by using xml_base::name(const Ch *) or xml_base::value(const Ch *) functions. Care must be taken to ensure that lifetime of the string passed is at least as long as lifetime of the node/attribute. The easiest way to achieve it is to allocate the string from memory_pool owned by the document. Use memory_pool::allocate_string() function for this purpose.

    3.3 Destructive Vs Non-Destructive Mode

    By default, the parser modifies source text during the parsing process. This is required to achieve character entity translation, whitespace normalization, and zero-termination of strings.

    + In some cases this behaviour may be undesirable, for example if source text resides in read only memory, or is mapped to memory directly from file. By using appropriate parser flags (parse_non_destructive), source text modifications can be disabled. However, because RapidXml does in-situ parsing, it obviously has the following side-effects:

    4. Performance

    RapidXml achieves its speed through use of several techniques:
    • In-situ parsing. When building DOM tree, RapidXml does not make copies of string data, such as node names and values. Instead, it stores pointers to interior of the source text.
    • Use of template metaprogramming techniques. This allows it to move much of the work to compile time. Through magic of the templates, C++ compiler generates a separate copy of parsing code for any combination of parser flags you use. In each copy, all possible decisions are made at compile time and all unused code is omitted.
    • Extensive use of lookup tables for parsing.
    • Hand-tuned C++ with profiling done on several most popular CPUs.
    This results in a very small and fast code: a parser which is custom tailored to exact needs with each invocation.

    4.1 Comparison With Other Parsers

    The table below compares speed of RapidXml to some other parsers, and to strlen() function executed on the same data. On a modern CPU (as of 2007), you can expect parsing throughput to be close to 1 GB/s. As a rule of thumb, parsing speed is about 50-100x faster than Xerces DOM, 30-60x faster than TinyXml, 3-12x faster than pugxml, and about 5% - 30% faster than pugixml, the fastest XML parser I know of.
    • The test file is a real-world, 50kB large, moderately dense XML file.
    • All timing is done by using RDTSC instruction present in Pentium-compatible CPUs.
    • No profile-guided optimizations are used.
    • All parsers are running in their fastest modes.
    • The results are given in CPU cycles per character, so frequency of CPUs is irrelevant.
    • The results are minimum values from a large number of runs, to minimize effects of operating system activity, task switching, interrupt handling etc.
    • A single parse of the test file takes about 1/10th of a millisecond, so with large number of runs there is a good chance of hitting at least one no-interrupt streak, and obtaining undisturbed results.
    Platform
    Compiler
    strlen() RapidXml pugixml 0.3 pugxml TinyXml
    Pentium 4
    MSVC 8.0
    2.5
    5.4
    7.0
    61.7
    298.8
    Pentium 4
    gcc 4.1.1
    0.8
    6.1
    9.5
    67.0
    413.2
    Core 2
    MSVC 8.0
    1.0
    4.5
    5.0
    24.6
    154.8
    Core 2
    gcc 4.1.1
    0.6
    4.6
    5.4
    28.3
    229.3
    Athlon XP
    MSVC 8.0
    3.1
    7.7
    8.0
    25.5
    182.6
    Athlon XP
    gcc 4.1.1
    0.9
    8.2
    9.2
    33.7
    265.2
    Pentium 3
    MSVC 8.0
    2.0
    6.3
    7.0
    30.9
    211.9
    Pentium 3
    gcc 4.1.1
    1.0
    6.7
    8.9
    35.3
    316.0
    (*) All results are in CPU cycles per character of source text

    5. Reference

    This section lists all classes, functions, constants etc. and describes them in detail.
    class + template + rapidxml::memory_pool
    + constructor + memory_pool()
    + destructor + ~memory_pool()
    function allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
    function allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
    function allocate_string(const Ch *source=0, std::size_t size=0)
    function clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0)
    function clear()
    function set_allocator(alloc_func *af, free_func *ff)

    class rapidxml::parse_error
    + constructor + parse_error(const char *what, void *where)
    function what() const
    function where() const

    class + template + rapidxml::xml_attribute
    + constructor + xml_attribute()
    function document() const
    function previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const

    class + template + rapidxml::xml_base
    + constructor + xml_base()
    function name() const
    function name_size() const
    function value() const
    function value_size() const
    function name(const Ch *name, std::size_t size)
    function name(const Ch *name)
    function value(const Ch *value, std::size_t size)
    function value(const Ch *value)
    function parent() const

    class + template + rapidxml::xml_document
    + constructor + xml_document()
    function parse(Ch *text)
    function clear()

    class + template + rapidxml::xml_node
    + constructor + xml_node(node_type type)
    function type() const
    function document() const
    function first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
    function type(node_type type)
    function prepend_node(xml_node< Ch > *child)
    function append_node(xml_node< Ch > *child)
    function insert_node(xml_node< Ch > *where, xml_node< Ch > *child)
    function remove_first_node()
    function remove_last_node()
    function remove_node(xml_node< Ch > *where)
    function remove_all_nodes()
    function prepend_attribute(xml_attribute< Ch > *attribute)
    function append_attribute(xml_attribute< Ch > *attribute)
    function insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute)
    function remove_first_attribute()
    function remove_last_attribute()
    function remove_attribute(xml_attribute< Ch > *where)
    function remove_all_attributes()

    namespace rapidxml
    enum node_type
    function parse_error_handler(const char *what, void *where)
    function print(OutIt out, const xml_node< Ch > &node, int flags=0)
    function print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0)
    function operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node)
    + constant + parse_no_data_nodes
    + constant + parse_no_element_values
    + constant + parse_no_string_terminators
    + constant + parse_no_entity_translation
    + constant + parse_no_utf8
    + constant + parse_declaration_node
    + constant + parse_comment_nodes
    + constant + parse_doctype_node
    + constant + parse_pi_nodes
    + constant + parse_validate_closing_tags
    + constant + parse_trim_whitespace
    + constant + parse_normalize_whitespace
    + constant + parse_default
    + constant + parse_non_destructive
    + constant + parse_fastest
    + constant + parse_full
    + constant + print_no_indenting


    class + template + rapidxml::memory_pool

    + + Defined in rapidxml.hpp
    + Base class for + xml_document

    Description

    This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. In most cases, you will not need to use this class directly. However, if you need to create nodes manually or modify names/values of nodes, you are encouraged to use memory_pool of relevant xml_document to allocate the memory. Not only is this faster than allocating them by using new operator, but also their lifetime will be tied to the lifetime of document, possibly simplyfing memory management.

    + Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. You can also call allocate_string() function to allocate strings. Such strings can then be used as names or values of nodes without worrying about their lifetime. Note that there is no free() function -- all allocations are freed at once when clear() function is called, or when the pool is destroyed.

    + It is also possible to create a standalone memory_pool, and use it to allocate nodes, whose lifetime will not be tied to any document.

    + Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. Until static memory is exhausted, no dynamic memory allocations are done. When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, by using global new[] and delete[] operators. This behaviour can be changed by setting custom allocation routines. Use set_allocator() function to set them.

    + Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. This value defaults to the size of pointer on target architecture.

    + To obtain absolutely top performance from the parser, it is important that all nodes are allocated from a single, contiguous block of memory. Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT to obtain best wasted memory to performance compromise. To do it, define their values before rapidxml.hpp file is included.

    Parameters

    Ch
    Character type of created nodes.

    + constructor + memory_pool::memory_pool

    Synopsis

    memory_pool(); +

    Description

    Constructs empty pool with default allocator functions.

    + destructor + memory_pool::~memory_pool

    Synopsis

    ~memory_pool(); +

    Description

    Destroys pool and frees all the memory. This causes memory occupied by nodes allocated by the pool to be freed. Nodes allocated from the pool are no longer valid.

    function memory_pool::allocate_node

    Synopsis

    xml_node<Ch>* allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

    Description

    Allocates a new node from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

    Parameters

    type
    Type of node to create.
    name
    Name to assign to the node, or 0 to assign no name.
    value
    Value to assign to the node, or 0 to assign no value.
    name_size
    Size of name to assign, or 0 to automatically calculate size from name string.
    value_size
    Size of value to assign, or 0 to automatically calculate size from value string.

    Returns

    Pointer to allocated node. This pointer will never be NULL.

    function memory_pool::allocate_attribute

    Synopsis

    xml_attribute<Ch>* allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0); +

    Description

    Allocates a new attribute from the pool, and optionally assigns name and value to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

    Parameters

    name
    Name to assign to the attribute, or 0 to assign no name.
    value
    Value to assign to the attribute, or 0 to assign no value.
    name_size
    Size of name to assign, or 0 to automatically calculate size from name string.
    value_size
    Size of value to assign, or 0 to automatically calculate size from value string.

    Returns

    Pointer to allocated attribute. This pointer will never be NULL.

    function memory_pool::allocate_string

    Synopsis

    Ch* allocate_string(const Ch *source=0, std::size_t size=0); +

    Description

    Allocates a char array of given size from the pool, and optionally copies a given string to it. If the allocation request cannot be accomodated, this function will throw std::bad_alloc. If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call rapidxml::parse_error_handler() function.

    Parameters

    source
    String to initialize the allocated memory with, or 0 to not initialize it.
    size
    Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.

    Returns

    Pointer to allocated char array. This pointer will never be NULL.

    function memory_pool::clone_node

    Synopsis

    xml_node<Ch>* clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0); +

    Description

    Clones an xml_node and its hierarchy of child nodes and attributes. Nodes and attributes are allocated from this memory pool. Names and values are not cloned, they are shared between the clone and the source. Result node can be optionally specified as a second parameter, in which case its contents will be replaced with cloned source node. This is useful when you want to clone entire document.

    Parameters

    source
    Node to clone.
    result
    Node to put results in, or 0 to automatically allocate result node

    Returns

    Pointer to cloned node. This pointer will never be NULL.

    function memory_pool::clear

    Synopsis

    void clear(); +

    Description

    Clears the pool. This causes memory occupied by nodes allocated by the pool to be freed. Any nodes or strings allocated from the pool will no longer be valid.

    function memory_pool::set_allocator

    Synopsis

    void set_allocator(alloc_func *af, free_func *ff); +

    Description

    Sets or resets the user-defined memory allocation functions for the pool. This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. Allocation function must not return invalid pointer on failure. It should either throw, stop the program, or use longjmp() function to pass control to other place of program. If it returns invalid pointer, results are undefined.

    + User defined allocation functions must have the following forms:

    +void *allocate(std::size_t size);
    +void free(void *pointer);

    Parameters

    af
    Allocation function, or 0 to restore default function
    ff
    Free function, or 0 to restore default function

    class rapidxml::parse_error

    + + Defined in rapidxml.hpp

    Description

    Parse error exception. This exception is thrown by the parser when an error occurs. Use what() function to get human-readable error message. Use where() function to get a pointer to position within source text where error was detected.

    + If throwing exceptions by the parser is undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. This function must be defined by the user.

    + This class derives from std::exception class.

    + constructor + parse_error::parse_error

    Synopsis

    parse_error(const char *what, void *where); +

    Description

    Constructs parse error.

    function parse_error::what

    Synopsis

    virtual const char* what() const; +

    Description

    Gets human readable description of error.

    Returns

    Pointer to null terminated description of the error.

    function parse_error::where

    Synopsis

    Ch* where() const; +

    Description

    Gets pointer to character data where error happened. Ch should be the same as char type of xml_document that produced the error.

    Returns

    Pointer to location within the parsed string where error occured.

    class + template + rapidxml::xml_attribute

    + + Defined in rapidxml.hpp
    + Inherits from + xml_base

    Description

    Class representing attribute node of XML document. Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). Note that after parse, both name and value of attribute will point to interior of source text used for parsing. Thus, this text must persist in memory for the lifetime of attribute.

    Parameters

    Ch
    Character type to use.

    + constructor + xml_attribute::xml_attribute

    Synopsis

    xml_attribute(); +

    Description

    Constructs an empty attribute with the specified type. Consider using memory_pool of appropriate xml_document if allocating attributes manually.

    function xml_attribute::document

    Synopsis

    xml_document<Ch>* document() const; +

    Description

    Gets document of which attribute is a child.

    Returns

    Pointer to document that contains this attribute, or 0 if there is no parent document.

    function xml_attribute::previous_attribute

    Synopsis

    xml_attribute<Ch>* previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets previous attribute, optionally matching attribute name.

    Parameters

    name
    Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found attribute, or 0 if not found.

    function xml_attribute::next_attribute

    Synopsis

    xml_attribute<Ch>* next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets next attribute, optionally matching attribute name.

    Parameters

    name
    Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found attribute, or 0 if not found.

    class + template + rapidxml::xml_base

    + + Defined in rapidxml.hpp
    + Base class for + xml_attribute xml_node

    Description

    Base class for xml_node and xml_attribute implementing common functions: name(), name_size(), value(), value_size() and parent().

    Parameters

    Ch
    Character type to use

    + constructor + xml_base::xml_base

    Synopsis

    xml_base(); +

    function xml_base::name

    Synopsis

    Ch* name() const; +

    Description

    Gets name of the node. Interpretation of name depends on type of node. Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

    + Use name_size() function to determine length of the name.

    Returns

    Name of node, or empty string if node has no name.

    function xml_base::name_size

    Synopsis

    std::size_t name_size() const; +

    Description

    Gets size of node name, not including terminator character. This function works correctly irrespective of whether name is or is not zero terminated.

    Returns

    Size of node name, in characters.

    function xml_base::value

    Synopsis

    Ch* value() const; +

    Description

    Gets value of node. Interpretation of value depends on type of node. Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.

    + Use value_size() function to determine length of the value.

    Returns

    Value of node, or empty string if node has no value.

    function xml_base::value_size

    Synopsis

    std::size_t value_size() const; +

    Description

    Gets size of node value, not including terminator character. This function works correctly irrespective of whether value is or is not zero terminated.

    Returns

    Size of node value, in characters.

    function xml_base::name

    Synopsis

    void name(const Ch *name, std::size_t size); +

    Description

    Sets name of node to a non zero-terminated string. See Ownership Of Strings .

    + Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

    + Size of name must be specified separately, because name does not have to be zero terminated. Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).

    Parameters

    name
    Name of node to set. Does not have to be zero terminated.
    size
    Size of name, in characters. This does not include zero terminator, if one is present.

    function xml_base::name

    Synopsis

    void name(const Ch *name); +

    Description

    Sets name of node to a zero-terminated string. See also Ownership Of Strings and xml_node::name(const Ch *, std::size_t).

    Parameters

    name
    Name of node to set. Must be zero terminated.

    function xml_base::value

    Synopsis

    void value(const Ch *value, std::size_t size); +

    Description

    Sets value of node to a non zero-terminated string. See Ownership Of Strings .

    + Note that node does not own its name or value, it only stores a pointer to it. It will not delete or otherwise free the pointer on destruction. It is reponsibility of the user to properly manage lifetime of the string. The easiest way to achieve it is to use memory_pool of the document to allocate the string - on destruction of the document the string will be automatically freed.

    + Size of value must be specified separately, because it does not have to be zero terminated. Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).

    + If an element has a child node of type node_data, it will take precedence over element value when printing. If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.

    Parameters

    value
    value of node to set. Does not have to be zero terminated.
    size
    Size of value, in characters. This does not include zero terminator, if one is present.

    function xml_base::value

    Synopsis

    void value(const Ch *value); +

    Description

    Sets value of node to a zero-terminated string. See also Ownership Of Strings and xml_node::value(const Ch *, std::size_t).

    Parameters

    value
    Vame of node to set. Must be zero terminated.

    function xml_base::parent

    Synopsis

    xml_node<Ch>* parent() const; +

    Description

    Gets node parent.

    Returns

    Pointer to parent node, or 0 if there is no parent.

    class + template + rapidxml::xml_document

    + + Defined in rapidxml.hpp
    + Inherits from + xml_node memory_pool

    Description

    This class represents root of the DOM hierarchy. It is also an xml_node and a memory_pool through public inheritance. Use parse() function to build a DOM tree from a zero-terminated XML text string. parse() function allocates memory for nodes and attributes by using functions of xml_document, which are inherited from memory_pool. To access root node of the document, use the document itself, as if it was an xml_node.

    Parameters

    Ch
    Character type to use.

    + constructor + xml_document::xml_document

    Synopsis

    xml_document(); +

    Description

    Constructs empty XML document.

    function xml_document::parse

    Synopsis

    void parse(Ch *text); +

    Description

    Parses zero-terminated XML string according to given flags. Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. The string must persist for the lifetime of the document. In case of error, rapidxml::parse_error exception will be thrown.

    + If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. Make sure that data is zero-terminated.

    + Document can be parsed into multiple times. Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.

    Parameters

    text
    XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.

    function xml_document::clear

    Synopsis

    void clear(); +

    Description

    Clears the document by deleting all nodes and clearing the memory pool. All nodes owned by document pool are destroyed.

    class + template + rapidxml::xml_node

    + + Defined in rapidxml.hpp
    + Inherits from + xml_base
    + Base class for + xml_document

    Description

    Class representing a node of XML document. Each node may have associated name and value strings, which are available through name() and value() functions. Interpretation of name and value depends on type of the node. Type of node can be determined by using type() function.

    + Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. Thus, this text must persist in the memory for the lifetime of node.

    Parameters

    Ch
    Character type to use.

    + constructor + xml_node::xml_node

    Synopsis

    xml_node(node_type type); +

    Description

    Constructs an empty node with the specified type. Consider using memory_pool of appropriate document to allocate nodes manually.

    Parameters

    type
    Type of node to construct.

    function xml_node::type

    Synopsis

    node_type type() const; +

    Description

    Gets type of node.

    Returns

    Type of node.

    function xml_node::document

    Synopsis

    xml_document<Ch>* document() const; +

    Description

    Gets document of which node is a child.

    Returns

    Pointer to document that contains this node, or 0 if there is no parent document.

    function xml_node::first_node

    Synopsis

    xml_node<Ch>* first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets first child node, optionally matching node name.

    Parameters

    name
    Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found child, or 0 if not found.

    function xml_node::last_node

    Synopsis

    xml_node<Ch>* last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets last child node, optionally matching node name. Behaviour is undefined if node has no children. Use first_node() to test if node has children.

    Parameters

    name
    Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found child, or 0 if not found.

    function xml_node::previous_sibling

    Synopsis

    xml_node<Ch>* previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets previous sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

    Parameters

    name
    Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found sibling, or 0 if not found.

    function xml_node::next_sibling

    Synopsis

    xml_node<Ch>* next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets next sibling node, optionally matching node name. Behaviour is undefined if node has no parent. Use parent() to test if node has a parent.

    Parameters

    name
    Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found sibling, or 0 if not found.

    function xml_node::first_attribute

    Synopsis

    xml_attribute<Ch>* first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets first attribute of node, optionally matching attribute name.

    Parameters

    name
    Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found attribute, or 0 if not found.

    function xml_node::last_attribute

    Synopsis

    xml_attribute<Ch>* last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const; +

    Description

    Gets last attribute of node, optionally matching attribute name.

    Parameters

    name
    Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
    name_size
    Size of name, in characters, or 0 to have size calculated automatically from string
    case_sensitive
    Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters

    Returns

    Pointer to found attribute, or 0 if not found.

    function xml_node::type

    Synopsis

    void type(node_type type); +

    Description

    Sets type of node.

    Parameters

    type
    Type of node to set.

    function xml_node::prepend_node

    Synopsis

    void prepend_node(xml_node< Ch > *child); +

    Description

    Prepends a new child node. The prepended child becomes the first child, and all existing children are moved one position back.

    Parameters

    child
    Node to prepend.

    function xml_node::append_node

    Synopsis

    void append_node(xml_node< Ch > *child); +

    Description

    Appends a new child node. The appended child becomes the last child.

    Parameters

    child
    Node to append.

    function xml_node::insert_node

    Synopsis

    void insert_node(xml_node< Ch > *where, xml_node< Ch > *child); +

    Description

    Inserts a new child node at specified place inside the node. All children after and including the specified node are moved one position back.

    Parameters

    where
    Place where to insert the child, or 0 to insert at the back.
    child
    Node to insert.

    function xml_node::remove_first_node

    Synopsis

    void remove_first_node(); +

    Description

    Removes first child node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

    function xml_node::remove_last_node

    Synopsis

    void remove_last_node(); +

    Description

    Removes last child of the node. If node has no children, behaviour is undefined. Use first_node() to test if node has children.

    function xml_node::remove_node

    Synopsis

    void remove_node(xml_node< Ch > *where); +

    Description

    Removes specified child from the node.

    function xml_node::remove_all_nodes

    Synopsis

    void remove_all_nodes(); +

    Description

    Removes all child nodes (but not attributes).

    function xml_node::prepend_attribute

    Synopsis

    void prepend_attribute(xml_attribute< Ch > *attribute); +

    Description

    Prepends a new attribute to the node.

    Parameters

    attribute
    Attribute to prepend.

    function xml_node::append_attribute

    Synopsis

    void append_attribute(xml_attribute< Ch > *attribute); +

    Description

    Appends a new attribute to the node.

    Parameters

    attribute
    Attribute to append.

    function xml_node::insert_attribute

    Synopsis

    void insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute); +

    Description

    Inserts a new attribute at specified place inside the node. All attributes after and including the specified attribute are moved one position back.

    Parameters

    where
    Place where to insert the attribute, or 0 to insert at the back.
    attribute
    Attribute to insert.

    function xml_node::remove_first_attribute

    Synopsis

    void remove_first_attribute(); +

    Description

    Removes first attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

    function xml_node::remove_last_attribute

    Synopsis

    void remove_last_attribute(); +

    Description

    Removes last attribute of the node. If node has no attributes, behaviour is undefined. Use first_attribute() to test if node has attributes.

    function xml_node::remove_attribute

    Synopsis

    void remove_attribute(xml_attribute< Ch > *where); +

    Description

    Removes specified attribute from node.

    Parameters

    where
    Pointer to attribute to be removed.

    function xml_node::remove_all_attributes

    Synopsis

    void remove_all_attributes(); +

    Description

    Removes all attributes of node.

    enum node_type

    Description

    Enumeration listing all node types produced by the parser. Use xml_node::type() function to query node type.

    Values

    node_document
    A document node. Name and value are empty.
    node_element
    An element node. Name contains element name. Value contains text of first data node.
    node_data
    A data node. Name is empty. Value contains data text.
    node_cdata
    A CDATA node. Name is empty. Value contains data text.
    node_comment
    A comment node. Name is empty. Value contains comment text.
    node_declaration
    A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
    node_doctype
    A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
    node_pi
    A PI node. Name contains target. Value contains instructions.

    function parse_error_handler

    Synopsis

    void rapidxml::parse_error_handler(const char *what, void *where); +

    Description

    When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function is called to notify user about the error. It must be defined by the user.

    + This function cannot return. If it does, the results are undefined.

    + A very simple definition might look like that: + void rapidxml::parse_error_handler(const char *what, void *where) + { + std::cout << "Parse error: " << what << "\n"; + std::abort(); + } +

    Parameters

    what
    Human readable description of the error.
    where
    Pointer to character data where error was detected.

    function print

    Synopsis

    OutIt rapidxml::print(OutIt out, const xml_node< Ch > &node, int flags=0); +

    Description

    Prints XML to given output iterator.

    Parameters

    out
    Output iterator to print to.
    node
    Node to be printed. Pass xml_document to print entire document.
    flags
    Flags controlling how XML is printed.

    Returns

    Output iterator pointing to position immediately after last character of printed text.

    function print

    Synopsis

    std::basic_ostream<Ch>& rapidxml::print(std::basic_ostream< Ch > &out, const xml_node< Ch > &node, int flags=0); +

    Description

    Prints XML to given output stream.

    Parameters

    out
    Output stream to print to.
    node
    Node to be printed. Pass xml_document to print entire document.
    flags
    Flags controlling how XML is printed.

    Returns

    Output stream.

    function operator<<

    Synopsis

    std::basic_ostream<Ch>& rapidxml::operator<<(std::basic_ostream< Ch > &out, const xml_node< Ch > &node); +

    Description

    Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.

    Parameters

    out
    Output stream to print to.
    node
    Node to be printed.

    Returns

    Output stream.

    + constant + parse_no_data_nodes

    Synopsis

    const int parse_no_data_nodes + = 0x1; +

    Description

    Parse flag instructing the parser to not create data nodes. Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_no_element_values

    Synopsis

    const int parse_no_element_values + = 0x2; +

    Description

    Parse flag instructing the parser to not use text of first data node as a value of parent element. Can be combined with other flags by use of | operator. Note that child data nodes of element node take precendence over its value when printing. That is, if element has one or more child data nodes and a value, the value will be ignored. Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.

    + See xml_document::parse() function.

    + constant + parse_no_string_terminators

    Synopsis

    const int parse_no_string_terminators + = 0x4; +

    Description

    Parse flag instructing the parser to not place zero terminators after strings in the source text. By default zero terminators are placed, modifying source text. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_no_entity_translation

    Synopsis

    const int parse_no_entity_translation + = 0x8; +

    Description

    Parse flag instructing the parser to not translate entities in the source text. By default entities are translated, modifying source text. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_no_utf8

    Synopsis

    const int parse_no_utf8 + = 0x10; +

    Description

    Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. By default, UTF-8 handling is enabled. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_declaration_node

    Synopsis

    const int parse_declaration_node + = 0x20; +

    Description

    Parse flag instructing the parser to create XML declaration node. By default, declaration node is not created. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_comment_nodes

    Synopsis

    const int parse_comment_nodes + = 0x40; +

    Description

    Parse flag instructing the parser to create comments nodes. By default, comment nodes are not created. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_doctype_node

    Synopsis

    const int parse_doctype_node + = 0x80; +

    Description

    Parse flag instructing the parser to create DOCTYPE node. By default, doctype node is not created. Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_pi_nodes

    Synopsis

    const int parse_pi_nodes + = 0x100; +

    Description

    Parse flag instructing the parser to create PI nodes. By default, PI nodes are not created. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_validate_closing_tags

    Synopsis

    const int parse_validate_closing_tags + = 0x200; +

    Description

    Parse flag instructing the parser to validate closing tag names. If not set, name inside closing tag is irrelevant to the parser. By default, closing tags are not validated. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_trim_whitespace

    Synopsis

    const int parse_trim_whitespace + = 0x400; +

    Description

    Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. By default, whitespace is not trimmed. This flag does not cause the parser to modify source text. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_normalize_whitespace

    Synopsis

    const int parse_normalize_whitespace + = 0x800; +

    Description

    Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. By default, whitespace is not normalized. If this flag is specified, source text will be modified. Can be combined with other flags by use of | operator.

    + See xml_document::parse() function.

    + constant + parse_default

    Synopsis

    const int parse_default + = 0; +

    Description

    Parse flags which represent default behaviour of the parser. This is always equal to 0, so that all other flags can be simply ored together. Normally there is no need to inconveniently disable flags by anding with their negated (~) values. This also means that meaning of each flag is a negation of the default setting. For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, and using the flag will disable it.

    + See xml_document::parse() function.

    + constant + parse_non_destructive

    Synopsis

    const int parse_non_destructive + = parse_no_string_terminators | parse_no_entity_translation; +

    Description

    A combination of parse flags that forbids any modifications of the source text. This also results in faster parsing. However, note that the following will occur:
    • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
    • entities will not be translated
    • whitespace will not be normalized
    +See xml_document::parse() function.

    + constant + parse_fastest

    Synopsis

    const int parse_fastest + = parse_non_destructive | parse_no_data_nodes; +

    Description

    A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.

    + See xml_document::parse() function.

    + constant + parse_full

    Synopsis

    const int parse_full + = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; +

    Description

    A combination of parse flags resulting in largest amount of data being extracted. This usually results in slowest parsing.

    + See xml_document::parse() function.

    + constant + print_no_indenting

    Synopsis

    const int print_no_indenting + = 0x1; +

    Description

    Printer flag instructing the printer to suppress indenting of XML. See print() function.

    \ No newline at end of file diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml.hpp new file mode 100644 index 000000000..ae91e081d --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml.hpp @@ -0,0 +1,2596 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

    + //! This function cannot return. If it does, the results are undefined. + //!

    + //! A very simple definition might look like that: + //!

    +    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
    +    //! {
    +    //!     std::cout << "Parse error: " << what << "\n";
    +    //!     std::abort();
    +    //! }
    +    //! 
    + //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

    + //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

    + //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

    + //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

    + //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

    + //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
      + //!
    • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
    • + //!
    • entities will not be translated
    • + //!
    • whitespace will not be normalized
    • + //!
    + //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

    + //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

    + //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

    + //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

    + //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

    + //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

    + //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

    + //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
    (align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

    + //! User defined allocation functions must have the following forms: + //!
    + //!
    void *allocate(std::size_t size); + //!
    void free(void *pointer); + //!

    + //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
    (pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

    + //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

    + //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

    + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

    + //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

    + //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

    + //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

    + //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

    + //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

    + //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

    + //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_iterators.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_iterators.hpp new file mode 100644 index 000000000..52ebc298a --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template + class node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_print.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_print.hpp new file mode 100644 index 000000000..0ae2b14fa --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include + #include +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + // Print children of the node + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template + inline OutIt print(OutIt out, const xml_node &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_utils.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_utils.hpp new file mode 100644 index 000000000..37c29535f --- /dev/null +++ b/doc/src/docutils/tools/doxygen_xml2qbk/contrib/rapidxml-1.13/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_elements.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_elements.hpp index 2667ed50b..04d50dcfa 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_elements.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_elements.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -22,18 +23,20 @@ enum function_type { function_unknown, function_define, - function_constructor, + function_constructor_destructor, function_member, - function_free + function_free, }; struct base_element { std::string name; std::string brief_description; - + bool skip; + std::string id; + base_element(std::string const& n = "") : name(n) , skip(false) @@ -47,6 +50,7 @@ struct parameter : public base_element std::string type; std::string default_value; // for template parameters std::string fulltype; // post-processed + std::string fulltype_without_links; }; struct enumeration_value : public base_element @@ -85,6 +89,12 @@ struct markup } }; +struct paragraph +{ + std::string title; + std::string text; +}; + // Base of a class/struct, function, define struct element : public base_element { @@ -103,6 +113,10 @@ struct element : public base_element std::vector template_parameters; std::vector parameters; + std::vector paragraphs; + std::string warning; + std::string note; + element() : line(0) {} @@ -114,12 +128,17 @@ struct function : public element function_type type; std::string definition, argsstring; std::string return_type, return_description; + std::string precondition; + + std::string return_type_without_links; + bool is_static, is_const, is_explicit, is_virtual; bool unique; function() : type(function_unknown) , unique(true) + , is_static(false), is_const(false), is_explicit(false), is_virtual(false) {} }; @@ -153,6 +172,9 @@ struct class_or_struct : public element struct documentation { + std::string group_id; + std::string group_title; + // Only one expected (no grouping) class_or_struct cos; diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml2qbk.cpp b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml2qbk.cpp index b436c523f..87ac68e07 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml2qbk.cpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml2qbk.cpp @@ -1,6 +1,7 @@ // doxml2qbk (developed in the context of Boost.Geometry documentation) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -18,8 +19,6 @@ // to an example. // - currently still in draft -// Aug 14/15: added classes, defines, various enhancements. - #include #include #include @@ -43,6 +42,23 @@ #include #include +static const std::string version = "1.1.0"; + +inline std::string program_description(bool decorated) +{ + std::string result; + if (decorated) + { + result = "=== "; + } + result += "doxygen_xml2qbk "; + result += version; + if (decorated) + { + result += " ==="; + } + return result; +} int main(int argc, char** argv) @@ -52,17 +68,18 @@ int main(int argc, char** argv) { configuration config; std::string copyright_filename; + std::string output_style; // Read/get configuration { namespace po = boost::program_options; - po::options_description description("=== doxml2qbk ===\nAllowed options"); - + po::options_description description; std::string convenience_headers; description.add_options() ("help", "Help message") + ("version", "Version description") ("xml", po::value(&filename), "Name of XML file written by Doxygen") ("start_include", po::value(&config.start_include), @@ -72,9 +89,12 @@ int main(int argc, char** argv) ("convenience_headers", po::value(&convenience_headers), "Convenience header(s) (comma-separated)") ("skip_namespace", po::value(&config.skip_namespace), - "Namespace to skip (e.g. boost::mylib::") + "Namespace to skip (e.g. boost::mylib::)") ("copyright", po::value(©right_filename), "Name of QBK file including (commented) copyright and license") + + ("output_style", po::value(&output_style), + "Docbook output style. Available values: 'alt'") ; po::variables_map varmap; @@ -92,9 +112,25 @@ int main(int argc, char** argv) po::notify(varmap); - if (varmap.count("help") || filename.empty()) + if (varmap.count("version")) { - std::cout << description << std::endl; + std::cout << version << std::endl; + return 0; + } + else if (varmap.count("help")) + { + std::cout + << program_description(true) << std::endl + << "Available options:" << std::endl + << description << std::endl; + return 0; + } + else if (filename.empty()) + { + std::cout + << program_description(true) << std::endl + << "Allowed options:" << std::endl + << description << std::endl; return 1; } @@ -105,6 +141,10 @@ int main(int argc, char** argv) } } + // Set output style + if ( "alt" == output_style ) + config.output_style = configuration::alt; + // Read files into strings std::string xml_string = file_to_string(filename); std::string license = copyright_filename.empty() @@ -146,29 +186,42 @@ int main(int argc, char** argv) // Write warning comment std::cout - << "[/ Generated by doxygen_xml2qbk, don't change, will be overwritten automatically]" << std::endl + << "[/ Generated by " << program_description(false) << ", don't change, will be overwritten automatically]" << std::endl << "[/ Generated from " << filename << "]" << std::endl; - // Write the rest: functions, defines, classes or structs - BOOST_FOREACH(function const& f, doc.functions) + if ( configuration::def == config.output_style ) { - quickbook_output(f, config, std::cout); - } - BOOST_FOREACH(function const& f, doc.defines) - { - quickbook_output(f, config, std::cout); - } - BOOST_FOREACH(enumeration const& e, doc.enumerations) - { - quickbook_output(e, config, std::cout); - } + // Write the rest: functions, defines, classes or structs + BOOST_FOREACH(function const& f, doc.functions) + { + quickbook_output(f, config, std::cout); + } + BOOST_FOREACH(function const& f, doc.defines) + { + quickbook_output(f, config, std::cout); + } + BOOST_FOREACH(enumeration const& e, doc.enumerations) + { + quickbook_output(e, config, std::cout); + } - if (! doc.cos.name.empty()) - { - std::sort(doc.cos.functions.begin(), doc.cos.functions.end(), sort_on_line()); - quickbook_output(doc.cos, config, std::cout); + if (! doc.cos.name.empty()) + { + std::sort(doc.cos.functions.begin(), doc.cos.functions.end(), sort_on_line()); + quickbook_output(doc.cos, config, std::cout); + } } + else if ( configuration::alt == config.output_style ) + { + if (! doc.cos.name.empty()) + { + std::sort(doc.cos.functions.begin(), doc.cos.functions.end(), sort_on_line()); + quickbook_output_alt(doc.cos, config, std::cout); + } + if ( !doc.group_id.empty() ) + quickbook_output_alt(doc, config, std::cout); + } } catch(std::exception const& e) { diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp index aa8b90219..0a98f4296 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/doxygen_xml_parser.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -62,7 +63,16 @@ This is used for different purposes within Doxygen. So we have to list explicitly either where to recurse, or where not to... */ -static void parse_para(rapidxml::xml_node<>* node, std::string& contents, bool& skip, bool first = true) + +// Type used to store parsing state. It indicates if QBK formatting block was opened - [*...], [^...], etc. +enum text_block +{ + not_in_block, + in_code_block, + in_block +}; + +static void parse_para(rapidxml::xml_node<>* node, configuration const& config, std::string& contents, bool& skip, bool first = true, text_block tb = not_in_block) { if (node != NULL) { @@ -70,18 +80,73 @@ static void parse_para(rapidxml::xml_node<>* node, std::string& contents, bool& { //std::cout << "ELEMENT: " << node->name() << "=" << node->value() << std::endl; std::string name = node->name(); - if (boost::equals(name, "qbk.skip")) + if ( boost::equals(name, "itemizedlist") ) { - skip = true; + contents += "\n\n"; + parse_para(node->first_node(), config, contents, skip, true, tb); + contents += "\n"; + parse_para(node->next_sibling(), config, contents, skip, true, tb); return; } + else if ( boost::equals(name, "listitem") ) + { + contents += "* "; + parse_para(node->first_node(), config, contents, skip, true, tb); + contents += "\n"; + parse_para(node->next_sibling(), config, contents, skip, true, tb); + return; + } + else if ( boost::equals(name, "verbatim") ) + { + contents += "\n``\n"; + parse_para(node->first_node(), config, contents, skip, false, tb); + contents += "``\n"; + parse_para(node->next_sibling(), config, contents, skip, false, tb); + return; + } + else if ( boost::equals(name, "bold") ) + { + contents += "[*"; + parse_para(node->first_node(), config, contents, skip, false, in_block); + contents += "]"; + parse_para(node->next_sibling(), config, contents, skip, false, tb); + return; + } + else if ( boost::equals(name, "emphasis") ) + { + contents += "['"; + parse_para(node->first_node(), config, contents, skip, false, in_block); + contents += "]"; + parse_para(node->next_sibling(), config, contents, skip, false, tb); + return; + } + else if ( boost::equals(name, "computeroutput") ) + { + contents += "[^"; + parse_para(node->first_node(), config, contents, skip, false, tb == in_block ? in_block : in_code_block); + contents += "]"; + parse_para(node->next_sibling(), config, contents, skip, false, tb); + return; + } + else if ( boost::equals(name, "ref") ) + { + // If alternative output is used - insert links + if ( configuration::alt == config.output_style ) + { + std::string refid = node->first_attribute("refid")->value(); + if ( !refid.empty() ) + { + contents += std::string("[link ") + refid + " "; + parse_para(node->first_node(), config, contents, skip, false, in_block); + contents += "]"; + parse_para(node->next_sibling(), config, contents, skip, false, tb); + return; + } + } + } else if (! ( (boost::equals(name, "para") && first) - || boost::equals(name, "ref") || boost::equals(name, "defval") - || boost::equals(name, "verbatim") - || boost::equals(name, "bold") - || boost::equals(name, "emphasis") || boost::equals(name, "linebreak") )) { @@ -90,20 +155,33 @@ static void parse_para(rapidxml::xml_node<>* node, std::string& contents, bool& } else if (node->type() == rapidxml::node_data) { - contents += node->value(); + std::string str = node->value(); + if ( tb == in_block ) + { + boost::replace_all(str, "\\", "\\\\"); + boost::replace_all(str, "[", "\\["); + boost::replace_all(str, "]", "\\]"); + } + else if ( tb == in_code_block ) + { + if ( str.find('`') == std::string::npos ) + str = std::string("`") + str + "`"; + } + contents += str; //std::cout << "DATA: " << node->name() << "=" << node->value() << std::endl; } else { //std::cout << "OTHER: " << node->name() << "=" << node->value() << std::endl; } - parse_para(node->first_node(), contents, skip, false); - parse_para(node->next_sibling(), contents, skip, false); + + parse_para(node->first_node(), config, contents, skip, false, tb); + parse_para(node->next_sibling(), config, contents, skip, false, tb); } } -static void parse_parameter(rapidxml::xml_node<>* node, parameter& p) +static void parse_parameter(rapidxml::xml_node<>* node, configuration const& config, parameter& p) { // #define: Point // template: typenameCoordinateTypeCoordinateType @@ -121,25 +199,33 @@ static void parse_parameter(rapidxml::xml_node<>* node, parameter& p) boost::replace_all(p.type, "&", ""); boost::replace_all(p.type, "*", ""); boost::trim(p.type); + + // If alt output is used retrieve type with QBK links + if ( configuration::alt == config.output_style ) + { + p.fulltype_without_links = p.fulltype; + p.fulltype.clear(); + parse_para(node->first_node(), config, p.fulltype, p.skip); + } } else if (name == "declname") p.name = node->value(); else if (name == "parametername") p.name = node->value(); else if (name == "defname") p.name = node->value(); else if (name == "defval") { - parse_para(node, p.default_value, p.skip); + parse_para(node, config, p.default_value, p.skip); } else if (name == "para") { - parse_para(node, p.brief_description, p.skip); + parse_para(node, config, p.brief_description, p.skip); } - parse_parameter(node->first_node(), p); - parse_parameter(node->next_sibling(), p); + parse_parameter(node->first_node(), config, p); + parse_parameter(node->next_sibling(), config, p); } } -static void parse_enumeration_value(rapidxml::xml_node<>* node, enumeration_value& value) +static void parse_enumeration_value(rapidxml::xml_node<>* node, configuration const& config, enumeration_value& value) { // green 2 // ... @@ -153,21 +239,21 @@ static void parse_enumeration_value(rapidxml::xml_node<>* node, enumeration_valu else if (node_name == "para") { // Parses both brief AND detailed into this description - parse_para(node, value.brief_description, value.skip); + parse_para(node, config, value.brief_description, value.skip); } else if (node_name == "initializer") { value.initializer = node->value(); } - parse_enumeration_value(node->first_node(), value); - parse_enumeration_value(node->next_sibling(), value); + parse_enumeration_value(node->first_node(), config, value); + parse_enumeration_value(node->next_sibling(), config, value); } } // Definition is a function or a class/struct template -static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& parameters) +static void parse_parameter_list(rapidxml::xml_node<>* node, configuration const& config, Parameters& parameters) { if (node != NULL) { @@ -176,7 +262,7 @@ static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& paramet if (name == "parameteritem") { parameter p; - parse_parameter(node->first_node(), p); + parse_parameter(node->first_node(), config, p); if (! p.name.empty()) { // Copy its description @@ -196,7 +282,7 @@ static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& paramet { // Element of 'templateparamlist.param (.type,.declname,.defname)' parameter p; - parse_parameter(node->first_node(), p); + parse_parameter(node->first_node(), config, p); // Doxygen handles templateparamlist param's differently: // @@ -223,8 +309,8 @@ static void parse_parameter_list(rapidxml::xml_node<>* node, Parameters& paramet add_or_set(parameters, p); } - parse_parameter_list(node->first_node(), parameters); - parse_parameter_list(node->next_sibling(), parameters); + parse_parameter_list(node->first_node(), config, parameters); + parse_parameter_list(node->next_sibling(), config, parameters); } } @@ -279,12 +365,12 @@ static void parse_element(rapidxml::xml_node<>* node, configuration const& confi if (full == ".briefdescription.para") { - parse_para(node, el.brief_description, el.skip); + parse_para(node, config, el.brief_description, el.skip); } else if (full == ".detaileddescription.para") { std::string para; - parse_para(node, para, el.skip); + parse_para(node, config, para, el.skip); if (!para.empty() && !el.detailed_description.empty()) { el.detailed_description += "\n\n"; @@ -323,7 +409,7 @@ static void parse_element(rapidxml::xml_node<>* node, configuration const& confi } else if (full == ".templateparamlist") { - parse_parameter_list(node->first_node(), el.template_parameters); + parse_parameter_list(node->first_node(), config, el.template_parameters); } else if (full == ".detaileddescription.para.parameterlist") { @@ -333,19 +419,43 @@ static void parse_element(rapidxml::xml_node<>* node, configuration const& confi // Parse parameters and their descriptions. // NOTE: they are listed here, but the order might not be the order in the function call std::vector parameters; - parse_parameter_list(node->first_node(), parameters); + parse_parameter_list(node->first_node(), config, parameters); copy_parameters_properties(parameters, el.parameters); } else if (kind == "templateparam") { - parse_parameter_list(node->first_node(), el.template_parameters); + parse_parameter_list(node->first_node(), config, el.template_parameters); + } + } + else if (full == ".detaileddescription.para.simplesect") + { + std::string kind = get_attribute(node, "kind"); + if (kind == "par") + { + paragraph p; + + rapidxml::xml_node<> * title_node = node->first_node("title"); + if ( title_node ) + p.title = title_node->value(); + + parse_para(node->first_node("para"), config, p.text, el.skip); + + el.paragraphs.push_back(p); + } + else if (kind == "warning") + { + parse_para(node->first_node("para"), config, el.warning, el.skip); + } + else if (kind == "note") + { + parse_para(node->first_node("para"), config, el.note, el.skip); } } else if (full == ".param") { // Parse one parameter, and add it to el.parameters parameter p; - parse_parameter(node->first_node(), p); + parse_parameter(node->first_node(), config, p); el.parameters.push_back(p); } @@ -375,24 +485,37 @@ static void parse_function(rapidxml::xml_node<>* node, configuration const& conf else if (full == ".param") { parameter p; - parse_parameter(node->first_node(), p); + parse_parameter(node->first_node(), config, p); add_or_set(f.parameters, p); } else if (full == ".type") { get_contents(node->first_node(), f.return_type); + + // If alt output is used, retrieve return type with links + if ( configuration::alt == config.output_style ) + { + f.return_type_without_links = f.return_type; + bool dummy_skip; + f.return_type.clear(); + parse_para(node->first_node(), config, f.return_type, dummy_skip); + } } else if (full == ".detaileddescription.para.simplesect") { std::string kind = get_attribute(node, "kind"); if (kind == "return") { - get_contents(node->first_node(), f.return_description); + parse_para(node->first_node(), config, f.return_description, f.skip); } /*else if (kind == "param") { get_contents(node->first_node(), f.paragraphs); }*/ + else if (kind == "pre") + { + parse_para(node->first_node(), config, f.precondition, f.skip); + } } else if (full == ".detaileddescription.para.image") { @@ -414,7 +537,7 @@ static void parse_enumeration(rapidxml::xml_node<>* node, configuration const& c else if (full == ".enumvalue") { enumeration_value value; - parse_enumeration_value(node->first_node(), value); + parse_enumeration_value(node->first_node(), config, value); e.enumeration_values.push_back(value); } @@ -479,35 +602,54 @@ static void parse(rapidxml::xml_node<>* node, configuration const& config, docum else if (nodename == "compounddef") { std::string kind = get_attribute(node, "kind"); + std::string id = get_attribute(node, "id"); if (kind == "group") { recurse = true; + doc.group_id = id; + rapidxml::xml_node<> * n = node->first_node("title"); + if ( n ) + doc.group_title = n->value(); } else if (kind == "struct") { recurse = true; doc.cos.is_class = false; + doc.cos.id = id; parse_element(node->first_node(), config, "", doc.cos); } else if (kind == "class") { recurse = true; doc.cos.is_class = true; + doc.cos.id = id; parse_element(node->first_node(), config, "", doc.cos); } } else if (nodename == "memberdef") { std::string kind = get_attribute(node, "kind"); + std::string id = get_attribute(node, "id"); + if (kind == "function") { function f; + f.id = id; + f.is_static = get_attribute(node, "static") == "yes" ? true : false; + f.is_const = get_attribute(node, "const") == "yes" ? true : false; + f.is_explicit = get_attribute(node, "explicit") == "yes" ? true : false; + f.is_virtual = get_attribute(node, "virt") == "virtual" ? true : false; + parse_element(node->first_node(), config, "", f); parse_function(node->first_node(), config, "", f); + if (member) { - f.type = boost::equals(f.name, doc.cos.name) - ? function_constructor + bool c_or_d = boost::equals(f.name, doc.cos.name) || + boost::equals(f.name, std::string("~") + doc.cos.name); + + f.type = c_or_d + ? function_constructor_destructor : function_member; doc.cos.functions.push_back(f); } @@ -520,14 +662,16 @@ static void parse(rapidxml::xml_node<>* node, configuration const& config, docum else if (kind == "define") { function f; + f.id = id; f.type = function_define; parse_element(node->first_node(), config, "", f); parse_function(node->first_node(), config, "", f); - doc.functions.push_back(f); + doc.defines.push_back(f); } else if (kind == "enum") { enumeration e; + e.id = id; parse_element(node->first_node(), config, "", e); parse_enumeration(node->first_node(), config, "", e); doc.enumerations.push_back(e); @@ -538,6 +682,11 @@ static void parse(rapidxml::xml_node<>* node, configuration const& config, docum { std::string name = parse_named_node(node->first_node(), "name"); doc.cos.typedefs.push_back(base_element(name)); + doc.cos.typedefs.back().id = id; + + element dummy; + parse_element(node->first_node(), config, "", dummy); + doc.cos.typedefs.back().brief_description = dummy.brief_description; } } else if (kind == "variable") @@ -548,6 +697,7 @@ static void parse(rapidxml::xml_node<>* node, configuration const& config, docum { std::string name = parse_named_node(node->first_node(), "name"); doc.cos.variables.push_back(base_element(name)); + doc.cos.variables.back().id = id; } } diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/file_to_string.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/file_to_string.hpp index e889fc75f..5af013056 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/file_to_string.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/file_to_string.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/parameter_predicates.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/parameter_predicates.hpp index 8cbb55e74..8d58709fb 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/parameter_predicates.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/parameter_predicates.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/quickbook_output.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/quickbook_output.hpp index 81714d8d5..6fe48a05a 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/quickbook_output.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/quickbook_output.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -58,7 +59,7 @@ std::string qbk_escaped(std::string const& s) -void quickbook_template_parameter_list(std::vector const& parameters, std::ostream& out, bool name = false) +void quickbook_template_parameter_list(std::vector const& parameters, std::ostream& out) { if (!parameters.empty()) { @@ -78,9 +79,10 @@ void quickbook_synopsis(function const& f, std::ostream& out) { out << "``"; quickbook_template_parameter_list(f.template_parameters, out); + switch(f.type) { - case function_constructor : + case function_constructor_destructor : out << f.name; break; case function_member : @@ -96,7 +98,7 @@ void quickbook_synopsis(function const& f, std::ostream& out) // do nothing break; } - + // Output the parameters // Because we want to be able to skip, we cannot use the argstring { @@ -139,7 +141,9 @@ void quickbook_synopsis(enumeration const& e, std::ostream& out) out << (first ? " {" : ", ") << value.name; if (! value.initializer.empty()) { - out << " = " << boost::trim_copy(value.initializer); + // Doxygen 1.6 does not include "=" in the tag, Doxygen 1.8 does. + // We just remove the "=" to have consisten output + out << " = " << boost::trim_copy(boost::replace_all_copy(value.initializer, "=", "")); } first = false; } @@ -418,7 +422,6 @@ void quickbook_output(function const& f, configuration const& config, std::ostre out << std::endl; } - void quickbook_output(enumeration const& e, configuration const& config, std::ostream& out) { out << "[section:" << to_section_name(e.name); @@ -469,12 +472,12 @@ void quickbook_output(enumeration const& e, configuration const& config, std::os out << std::endl; } -void quickbook_output_member(std::vector const& functions, - function_type type, - std::string const& title, - configuration const& config, std::ostream& out) +void quickbook_output_function(std::vector const& functions, + function_type type, + std::string const& title, + configuration const& config, std::ostream& out) { - std::string returns = type == function_constructor ? "" : " [Returns]"; + std::string returns = type == function_constructor_destructor ? "" : " [Returns]"; out << "[heading " << title << "(s)]" << std::endl << "[table" << std::endl << "[[Function] [Description] [Parameters] " << returns << "]" << std::endl; @@ -494,7 +497,6 @@ void quickbook_output_member(std::vector const& functions, << std::endl; } - void quickbook_output(class_or_struct const& cos, configuration const& config, std::ostream& out) { // Skip namespace @@ -584,14 +586,14 @@ void quickbook_output(class_or_struct const& cos, configuration const& config, s counts[f.type]++; } - if (counts[function_constructor] > 0) + if (counts[function_constructor_destructor] > 0) { - quickbook_output_member(cos.functions, function_constructor, "Constructor", config, out); + quickbook_output_function(cos.functions, function_constructor_destructor, "Constructor", config, out); } if (counts[function_member] > 0) { - quickbook_output_member(cos.functions, function_member, "Member Function", config, out); + quickbook_output_function(cos.functions, function_member, "Member Function", config, out); } quickbook_header(cos.location, config, out); @@ -602,4 +604,780 @@ void quickbook_output(class_or_struct const& cos, configuration const& config, s } +// ----------------------------------------------------------------------------------------------- // +// ALT +// ----------------------------------------------------------------------------------------------- // + +std::string remove_template_parameters(std::string const& name) +{ + std::string res; + std::string::size_type prev_i = 0, i = 0; + int blocks_counter = 0; + for ( ;; ) + { + std::string::size_type next_begin = name.find('<', i); + std::string::size_type next_end = name.find('>', i); + + if ( next_begin == next_end ) + { + res += name.substr(prev_i, next_begin - prev_i); + break; + } + else if ( next_begin < next_end ) + { + i = next_begin + 1; + if ( blocks_counter == 0 ) + res += name.substr(prev_i, next_begin - prev_i) + "<...>"; + blocks_counter++; + } + else + { + i = next_end + 1; + blocks_counter--; + if ( blocks_counter == 0 ) + prev_i = i; + } + } + + return res; +} + +std::string replace_brackets(std::string const& str) +{ + return boost::replace_all_copy(boost::replace_all_copy(str, "[", "\\["), "]", "\\]"); +} + +void quickbook_output_enumerations(std::vector const& enumerations, + configuration const& config, + std::ostream& out) +{ + out << "[table" << std::endl + << "[[Enumeration][Description]]" << std::endl; + + for ( size_t i = 0 ; i < enumerations.size() ; ++i ) + { + enumeration const& e = enumerations[i]; + + out << "[[[link " << e.id << " `"; + out << e.name; + out << "`]][" << e.brief_description << "]]" << std::endl; + } + out << "]" << std::endl + << std::endl; +} + +void quickbook_synopsis_short(function const& f, std::ostream& out) +{ + if ( f.type != function_unknown ) + out << f.name; + + bool first = true; + BOOST_FOREACH(parameter const& p, f.parameters) + { + if ( !p.skip && p.default_value.empty() ) + { + out << (first ? "(" : ", ") << remove_template_parameters(p.fulltype_without_links); + first = false; + } + } + + + if (! first) + out << ")"; + else if (f.type != function_define) + out << "()"; +} + +void quickbook_output_functions(std::vector const& functions, + function_type type, + configuration const& config, + std::ostream& out, + bool display_all = false, + std::string const& ColTitle = "Function") +{ + bool show_modifiers = false; + BOOST_FOREACH(function const& f, functions) + { + if ( (display_all || f.type == type) && (f.is_const || f.is_static) && !f.brief_description.empty() ) + show_modifiers = true; + } + + out << "[table\n" + << "["; + if ( show_modifiers ) + out << "[Modifier]"; + out << "[" << ColTitle << "]"; + out << "[Description]"; + out << "]" << std::endl; + + for ( size_t i = 0 ; i < functions.size() ; ++i ) + { + function const& f = functions[i]; + + if ( f.brief_description.empty() ) + continue; + + if (display_all || f.type == type) + { + out << "["; + if ( show_modifiers ) + { + out << "["; + out << (f.is_static ? "`static`" : ""); + out << (f.is_const ? " `const`" : ""); + out << "]"; + } + out << "[[link " << f.id << " `"; + quickbook_synopsis_short(f, out); + out << "`]]"; + out << "[" << f.brief_description << "]"; + out << "]" << std::endl; + } + } + out << "]" << std::endl + << std::endl; +} + +void output_paragraphs_note_warning(element const& el, std::ostream & out) +{ + // Additional paragraphs + if ( !el.paragraphs.empty() ) + { + BOOST_FOREACH(paragraph const& p, el.paragraphs) + { + if ( !p.title.empty() ) + out << "[heading " << p.title << "]" << std::endl; + else + out << "\n\n" << std::endl; + out << p.text << std::endl; + out << std::endl; + } + } + + // Note + if ( !el.note.empty() ) + { + out << "[note " << el.note << "]" << std::endl; + out << std::endl; + } + + // Warning + if ( !el.warning.empty() ) + { + out << "[warning " << el.warning << "]" << std::endl; + out << std::endl; + } +} + +void inline_str_with_links(std::string const& str, std::ostream & out) +{ + typedef std::string::size_type ST; + + bool link_started = false; + bool first = true; + for ( ST i = 0 ; i < str.size() ; ++i ) + { + if ( !link_started ) + { + if ( str[i] == '[' && str.substr(i, 6) == "[link " ) + { + if ( !first ) + { + out << "`"; + first = true; + } + link_started = true; + out << "[^[link "; + i += 5; // (+ 6 - 1) + } + else + { + if ( first ) + { + out << "`"; + first = false; + } + out << str[i]; + } + } + else + { + if ( str[i] == '\\' ) + { + out << str[i]; + ++i; + if ( i < str.size() ) + out << str[i]; + } + else if ( str[i] == ']' ) + { + out << "]]"; + link_started = false; + } + else + out << str[i]; + } + } + + if ( !first ) + out << "`"; + if ( link_started ) + out << "]]"; +} + +void quickbook_template_parameter_list_alt(std::vector const& parameters, std::ostream& out) +{ + std::string next_param; + + if ( 2 < parameters.size() ) + next_param = std::string("`,`\n") + " "; + else + next_param = "`,` "; + + if (!parameters.empty()) + { + out << "`template<`" ; + bool first = true; + BOOST_FOREACH(parameter const& p, parameters) + { + out << (first ? "" : next_param.c_str()); + inline_str_with_links(p.fulltype, out); + + if ( !p.default_value.empty() ) + { + out << " = "; + inline_str_with_links(p.default_value, out); + } + + first = false; + } + out << "`>`"; + } +} + +void quickbook_synopsis_alt(function const& f, std::ostream& out) +{ + out << "[pre\n"; + quickbook_template_parameter_list_alt(f.template_parameters, out); + out << "\n"; + + std::size_t offset = 1; // '(' + switch(f.type) + { + case function_constructor_destructor : + out << "`" << f.name << "`"; + offset += f.name.size(); + break; + case function_member : + inline_str_with_links(f.return_type, out); + out << " `" << f.name << "`"; + offset += f.return_type_without_links.size() + 1 + f.name.size(); + break; + case function_free : + inline_str_with_links(f.definition, out); + offset += f.definition.size(); + break; + case function_define : + out << "`#define " << f.name << "`"; + offset += 8 + f.name.size(); + break; + case function_unknown : + // do nothing + break; + } + + std::string par_end("`,` "); + if ( 2 < f.parameters.size() ) + par_end = std::string("`,`\n") + std::string(offset, ' '); + + // Output the parameters + // Because we want to be able to skip, we cannot use the argstring + { + bool first = true; + BOOST_FOREACH(parameter const& p, f.parameters) + { + if (! p.skip) + { + out << (first ? "`(`" : par_end); + if ( !p.fulltype.empty() ) + { + inline_str_with_links(p.fulltype, out); + out << " "; + } + if ( !p.name.empty() ) + out << "`" << p.name << "`"; + if ( !p.default_value.empty() ) + { + out << " = "; + inline_str_with_links(p.default_value, out); + } + first = false; + } + } + + if (! first) + out << "`)`\n"; + else if (f.type != function_define) + out << "`()`\n"; + } + + out << "]" + << std::endl + << std::endl; +} + +void quickbook_synopsis_alt(class_or_struct const& cos, configuration const& config, std::ostream & out) +{ + std::string short_name = namespace_skipped(cos.fullname, config); + + out << "[pre\n"; + + quickbook_template_parameter_list_alt(cos.template_parameters, out); + out << "\n"; + + out << (cos.is_class ? "`class " : "`struct "); + { + std::string::size_type last_scope = std::string::npos; + std::string::size_type i = short_name.find("<"); + for(std::string::size_type j = short_name.find("::") ; j < i ; j = short_name.find("::", j+1)) + last_scope = j; + if ( last_scope == std::string::npos ) + out << short_name << "`" << std::endl; + else + out << short_name.substr(last_scope + 2) << "`" << std::endl; + } + + if (! cos.base_classes.empty()) + { + out << "` : "; + bool first = true; + BOOST_FOREACH(base_class const& bc, cos.base_classes) + { + if (! first) + { + out << std::endl << " , "; + } + out << output_if_different(bc.derivation, "private") + << output_if_different(bc.virtuality, "non-virtual") + << namespace_skipped(bc.name, config); + first = false; + } + out << "`" << std::endl; + } + + out << "`{`" << std::endl + << "` // ...`" << std::endl + << "`};`" << std::endl + << "]" << std::endl << std::endl; +} + +void quickbook_synopsis_alt(enumeration const& e, std::ostream& out) +{ + std::string values_separator = + e.enumeration_values.size() <= 2 ? + std::string(", ") : + ( std::string(",\n") + std::string(e.name.size() + 7, ' ') ); + + out << "``enum " << e.name << " "; + bool first = true; + BOOST_FOREACH(enumeration_value const& value, e.enumeration_values) + { + out << (first ? "{" : values_separator.c_str()); + out << value.name; + if ( !value.initializer.empty() ) + { + out << " = " << boost::trim_copy(boost::replace_all_copy(value.initializer, "=", "")); + } + first = false; + } + if (! first) + { + out << "};"; + } + out << "``" + << std::endl + << std::endl; +} + +template +bool has_brief_description(Range const& rng) +{ + typedef typename Range::value_type V; + BOOST_FOREACH(V const& bc, rng) + { + if ( !bc.brief_description.empty() ) + return true; + } + return false; +} + +template +bool has_brief_description(Range const& rng, function_type t) +{ + typedef typename Range::value_type V; + BOOST_FOREACH(V const& bc, rng) + { + if ( bc.type == t && !bc.brief_description.empty() ) + return true; + } + return false; +} + +void quickbook_output_functions_details(std::vector const& functions, + function_type type, + configuration const& config, + std::ostream& out, + bool display_all = false) +{ + for ( size_t i = 0 ; i < functions.size() ; ++i ) + { + function const& f = functions[i]; + + if ( f.brief_description.empty() ) + continue; + + if ( display_all || f.type == type ) + { + // Section + std::stringstream ss; + quickbook_synopsis_short(f, ss); + out << "[#" << f.id << "]" << std::endl; + out << "[section " << replace_brackets(ss.str()) << "]" << std::endl; + + quickbook_output_indexterm(f.name, out); + + // Brief description + out << f.brief_description << std::endl; + out << std::endl; + + // Detail description + if ( !f.detailed_description.empty() ) + { + out << "[heading Description]" << std::endl; + out << f.detailed_description; + } + + // Synopsis + quickbook_markup(f.qbk_markup, markup_before, markup_synopsis, out); + out << "[heading Synopsis]" << std::endl; + quickbook_synopsis_alt(f, out); + quickbook_markup(f.qbk_markup, markup_after, markup_synopsis, out); + + if ( f.is_static || f.is_virtual || f.is_explicit || f.is_const ) + { + out << "[heading Modifier(s)]" << std::endl; + out << "``" + << (f.is_static ? "static " : "") + << (f.is_virtual ? "virtual " : "") + << (f.is_explicit ? "explicit " : "") + << (f.is_const ? "const " : "") + << "``"; + } + + // Template parameters + if ( !f.template_parameters.empty() && has_brief_description(f.template_parameters) ) + { + out << "[heading Template parameter(s)]" << std::endl + << "[table" << std::endl + << "[[Parameter] [Description]]" << std::endl; + + BOOST_FOREACH(parameter const& p, f.template_parameters) + { + if ( p.brief_description.empty() ) + continue; + + out << "[[`"; + if ( p.fulltype.find("typename ") == 0 ) + out << p.fulltype.substr(9); + else if ( p.fulltype.find("class ") == 0 ) + out << p.fulltype.substr(6); + else + out << p.fulltype; + out << "`][" << p.brief_description << "]]" << std::endl; + } + out << "]" << std::endl + << std::endl; + } + + // Parameters + if ( !f.parameters.empty() && has_brief_description(f.parameters) ) + { + out << "[heading Parameter(s)]" << std::endl; + out << "[table " << std::endl; + out << "["; + if ( f.type != function_define ) + out << "[Type]"; + out << "[Name][Description]]" << std::endl; + BOOST_FOREACH(parameter const& p, f.parameters) + { + if (!p.skip) + { + out << "["; + if ( f.type != function_define ) + { + out << "["; + inline_str_with_links(p.fulltype, out); + out << "]"; + } + out << "[ `" << p.name << "` ][" << p.brief_description << "]]"<< std::endl; + } + } + out << "]" << std::endl; + } + + // Precondition + if ( !f.precondition.empty() ) + { + out << "[heading Precondition(s)]" << std::endl; + out << f.precondition << std::endl; + out << std::endl; + } + + // Return + if ( !f.return_description.empty() ) + { + out << "[heading Returns]" << std::endl; + out << f.return_description << std::endl; + } + + // Additional paragraphs, note, warning + output_paragraphs_note_warning(f, out); + + // QBK markup + quickbook_markup(f.qbk_markup, markup_any, markup_default, out); + + // Section end + out << "[endsect]" << std::endl + //<< "[br]" << std::endl + << std::endl; + } + } +} + +void quickbook_output_enumeration_details(enumeration const& e, configuration const& config, std::ostream& out) +{ + out << "[#" << e.id << "]\n"; + out << "[section " << e.name << "]" << std::endl + << std::endl; + + quickbook_output_indexterm(e.name, out); + BOOST_FOREACH(enumeration_value const& value, e.enumeration_values) + { + quickbook_output_indexterm(value.name, out); + } + + out << e.brief_description << std::endl; + out << std::endl; + + if ( !e.detailed_description.empty() ) + { + out << "[heading Description]\n\n"; + out << e.detailed_description << "\n\n"; + } + + // Additional paragraphs, note, warning + output_paragraphs_note_warning(e, out); + + quickbook_markup(e.qbk_markup, markup_any, markup_default, out); + + // Synopsis + quickbook_markup(e.qbk_markup, markup_before, markup_synopsis, out); + out << "[heading Synopsis]" << std::endl; + quickbook_synopsis_alt(e, out); + quickbook_markup(e.qbk_markup, markup_after, markup_synopsis, out); + + + out << "[heading Values]" << std::endl + << std::endl; + + out << "[table" << std::endl << "["; + out << "[Value] [Description] ]" << std::endl; + + BOOST_FOREACH(enumeration_value const& value, e.enumeration_values) + { + out << "[[" << value.name << "] [" << value.brief_description << "]]\n"; + } + out << "]\n\n\n"; + + out << std::endl; + out << "[endsect]" << std::endl; + out << std::endl; +} + +void quickbook_output_alt(documentation const& doc, configuration const& config, std::ostream& out) +{ + if ( !doc.group_id.empty() ) + { + std::cout << "[section:" << doc.group_id << " " << doc.group_title << "]" << std::endl; + } + + if ( !doc.enumerations.empty() ) + { + std::cout << "[heading Enumerations]\n"; + quickbook_output_enumerations(doc.enumerations, config, out); + } + + if ( !doc.defines.empty() ) + { + std::cout << "[heading Defines]\n"; + quickbook_output_functions(doc.defines, function_unknown, config, out, true, "Define"); + } + + if ( !doc.functions.empty() ) + { + std::cout << "[heading Functions]\n"; + quickbook_output_functions(doc.functions, function_unknown, config, out, true, "Function"); + } + + BOOST_FOREACH(enumeration const& e, doc.enumerations) + { + quickbook_output_enumeration_details(e, config, out); + } + + quickbook_output_functions_details(doc.defines, function_unknown, config, out, true); + quickbook_output_functions_details(doc.functions, function_unknown, config, out, true); + + if ( !doc.group_id.empty() ) + { + out << "[endsect]" << std::endl + << std::endl; + } +} + +void quickbook_output_alt(class_or_struct const& cos, configuration const& config, std::ostream& out) +{ + // Skip namespace + std::string short_name = namespace_skipped(cos.fullname, config); + + BOOST_ASSERT(configuration::alt == config.output_style); + + if ( !cos.id.empty() ) + out << "[#" << cos.id << "]" << std::endl; + out << "[section " << short_name << "]" << std::endl << std::endl; + + // WARNING! Can't be used in the case of specializations + quickbook_output_indexterm(short_name, out); + + // Brief + + out << cos.brief_description << std::endl; + out << std::endl; + + // Description + + quickbook_string_with_heading_if_present("Description", cos.detailed_description, out); + + // Additional paragraphs, note, warning + output_paragraphs_note_warning(cos, out); + + // Markup + quickbook_markup(cos.qbk_markup, markup_any, markup_default, out); + + // Header + + quickbook_header(cos.location, config, out); + + // Class synposis + + quickbook_markup(cos.qbk_markup, markup_before, markup_synopsis, out); + out << "[heading Synopsis]" << std::endl; + quickbook_synopsis_alt(cos, config, out); + quickbook_markup(cos.qbk_markup, markup_after, markup_synopsis, out); + + // Template parameters + + if (! cos.template_parameters.empty()) + { + if ( has_brief_description(cos.template_parameters) ) + { + out << "[heading Template parameter(s)]" << std::endl + << "[table" << std::endl + << "[[Parameter] [Description]]" << std::endl; + + BOOST_FOREACH(parameter const& p, cos.template_parameters) + { + if ( p.brief_description.empty() ) + continue; + + out << "[[`"; + if ( p.fulltype.find("typename ") == 0 ) + out << p.fulltype.substr(9); + else if ( p.fulltype.find("class ") == 0 ) + out << p.fulltype.substr(6); + else + out << p.fulltype; + out << "`][" << p.brief_description << "]]" << std::endl; + } + out << "]" << std::endl + << std::endl; + } + } + + // Typedefs + + if ( !cos.typedefs.empty() ) + { + if ( has_brief_description(cos.typedefs) ) + { + out << "[heading Typedef(s)]" << std::endl + << "[table" << std::endl + << "[[Type]"; + out << " [Description]]" << std::endl; + + BOOST_FOREACH(base_element const& e, cos.typedefs) + { + if ( e.brief_description.empty() ) + continue; + + out << "[["; + if ( !e.id.empty() ) + out << "[#" << e.id << "]" << " "; + out << "`" << e.name << "`"; + out << "][" << e.brief_description << "]]" << std::endl; + } + out << "]" << std::endl + << std::endl; + } + } + + // Members + + bool display_ctors = has_brief_description(cos.functions, function_constructor_destructor); + bool display_members = has_brief_description(cos.functions, function_member); + + std::map counts; + BOOST_FOREACH(function const& f, cos.functions) + { + counts[f.type]++; + } + + if (display_ctors && counts[function_constructor_destructor] > 0) + { + out << "[heading Constructor(s) and destructor]" << std::endl; + quickbook_output_functions(cos.functions, function_constructor_destructor, config, out); + } + + if (display_members && counts[function_member] > 0) + { + out << "[heading Member(s)]" << std::endl; + quickbook_output_functions(cos.functions, function_member, config, out); + } + + // Details start + + //if ( display_ctors || display_members ) + // out << "[br]" << std::endl; + + if (display_ctors && counts[function_constructor_destructor] > 0) + quickbook_output_functions_details(cos.functions, function_constructor_destructor, config, out); + + if (display_members && counts[function_member] > 0) + quickbook_output_functions_details(cos.functions, function_member, config, out); + + // Details end + + out << "[endsect]" << std::endl + << std::endl; +} + #endif // QUICKBOOK_OUTPUT_HPP diff --git a/doc/src/docutils/tools/doxygen_xml2qbk/rapidxml_util.hpp b/doc/src/docutils/tools/doxygen_xml2qbk/rapidxml_util.hpp index 6acdaab5b..eea1f463c 100644 --- a/doc/src/docutils/tools/doxygen_xml2qbk/rapidxml_util.hpp +++ b/doc/src/docutils/tools/doxygen_xml2qbk/rapidxml_util.hpp @@ -1,6 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2010-2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/src/docutils/tools/support_status/support_status.cpp b/doc/src/docutils/tools/support_status/support_status.cpp index d3c788db3..5a8fa1e35 100644 --- a/doc/src/docutils/tools/support_status/support_status.cpp +++ b/doc/src/docutils/tools/support_status/support_status.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ #include #include #include +#include #include #include "text_outputter.hpp" @@ -132,6 +134,7 @@ DECLARE_UNARY_ALGORITHM(simplify) DECLARE_BINARY_ALGORITHM(transform) DECLARE_UNARY_ALGORITHM(unique) DECLARE_BINARY_ALGORITHM(within) +DECLARE_UNARY_ALGORITHM(wkt) template