s2/0000755000175000017510000000000015014114452010726 5ustar nileshnileshs2/man/0000755000175000017510000000000014737212474011517 5ustar nileshnileshs2/man/s2_cell.Rd0000644000175000017510000000452314737212474013335 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-cell.R \name{s2_cell} \alias{s2_cell} \alias{s2_cell_sentinel} \alias{s2_cell_invalid} \alias{as_s2_cell} \alias{as_s2_cell.s2_cell} \alias{as_s2_cell.character} \alias{as_s2_cell.s2_geography} \alias{as_s2_cell.wk_xy} \alias{as_s2_cell.integer64} \alias{new_s2_cell} \title{Create S2 Cell vectors} \usage{ s2_cell(x = character()) s2_cell_sentinel() s2_cell_invalid() as_s2_cell(x, ...) \method{as_s2_cell}{s2_cell}(x, ...) \method{as_s2_cell}{character}(x, ...) \method{as_s2_cell}{s2_geography}(x, ...) \method{as_s2_cell}{wk_xy}(x, ...) \method{as_s2_cell}{integer64}(x, ...) new_s2_cell(x) } \arguments{ \item{x}{The canonical S2 cell identifier as a character vector.} \item{...}{Passed to methods} } \value{ An object of class s2_cell } \description{ The S2 cell indexing system forms the basis for spatial indexing in the S2 library. On their own, S2 cells can represent points or areas. As a union, a vector of S2 cells can approximate a line or polygon. These functions allow direct access to the S2 cell indexing system and are designed to have minimal overhead such that looping and recursion have acceptable performance when used within R code. } \details{ Under the hood, S2 cell vectors are represented in R as vectors of type \code{\link[=double]{double()}}. This works because S2 cell identifiers are 64 bits wide, as are \code{double}s on all systems where R runs (The same trick is used by the bit64 package to represent signed 64-bit integers). As a happy accident, \code{NA_real_} is not a valid or meaningful cell identifier, so missing value support in the way R users might expect is preserved. It is worth noting that the underlying value of \code{s2_cell_sentinel()} would normally be considered \code{NA}; however, as it is meaningful and useful when programming with S2 cells, custom \code{is.na()} and comparison methods are implemented such that \code{s2_cell_sentinel()} is greater than all valid S2 cells and not considered missing. Users can and should implement compiled code that uses the underlying bytes of the vector, ensuring that the class of any returned object that should be interpreted in this way is constructed with \code{new_s2_cell()}. } \examples{ s2_cell("4b59a0cd83b5de49") as_s2_cell(s2_lnglat(-64, 45)) as_s2_cell(s2_data_cities("Ottawa")) } s2/man/s2_closest_feature.Rd0000644000175000017510000001067114737212474015606 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-matrix.R \name{s2_closest_feature} \alias{s2_closest_feature} \alias{s2_closest_edges} \alias{s2_farthest_feature} \alias{s2_distance_matrix} \alias{s2_max_distance_matrix} \alias{s2_contains_matrix} \alias{s2_within_matrix} \alias{s2_covers_matrix} \alias{s2_covered_by_matrix} \alias{s2_intersects_matrix} \alias{s2_disjoint_matrix} \alias{s2_equals_matrix} \alias{s2_touches_matrix} \alias{s2_dwithin_matrix} \alias{s2_may_intersect_matrix} \title{Matrix Functions} \usage{ s2_closest_feature(x, y) s2_closest_edges( x, y, k, min_distance = -1, max_distance = Inf, radius = s2_earth_radius_meters() ) s2_farthest_feature(x, y) s2_distance_matrix(x, y, radius = s2_earth_radius_meters()) s2_max_distance_matrix(x, y, radius = s2_earth_radius_meters()) s2_contains_matrix(x, y, options = s2_options(model = "open")) s2_within_matrix(x, y, options = s2_options(model = "open")) s2_covers_matrix(x, y, options = s2_options(model = "closed")) s2_covered_by_matrix(x, y, options = s2_options(model = "closed")) s2_intersects_matrix(x, y, options = s2_options()) s2_disjoint_matrix(x, y, options = s2_options()) s2_equals_matrix(x, y, options = s2_options()) s2_touches_matrix(x, y, options = s2_options()) s2_dwithin_matrix(x, y, distance, radius = s2_earth_radius_meters()) s2_may_intersect_matrix(x, y, max_edges_per_cell = 50, max_feature_cells = 4) } \arguments{ \item{x, y}{Geography vectors, coerced using \code{\link[=as_s2_geography]{as_s2_geography()}}. \code{x} is considered the source, where as \code{y} is considered the target.} \item{k}{The number of closest edges to consider when searching. Note that in S2 a point is also considered an edge.} \item{min_distance}{The minimum distance to consider when searching for edges. This filter is applied after the search is complete (i.e., may cause fewer than \code{k} values to be returned).} \item{max_distance}{The maximum distance to consider when searching for edges. This filter is applied before the search.} \item{radius}{Radius of the earth. Defaults to the average radius of the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.} \item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline model to use and the snap level.} \item{distance}{A distance on the surface of the earth in the same units as \code{radius}.} \item{max_edges_per_cell}{For \code{\link[=s2_may_intersect_matrix]{s2_may_intersect_matrix()}}, this values controls the nature of the index on \code{y}, with higher values leading to coarser index. Values should be between 10 and 50; the default of 50 is adequate for most use cases, but for specialized operations users may wish to use a lower value to increase performance.} \item{max_feature_cells}{For \code{\link[=s2_may_intersect_matrix]{s2_may_intersect_matrix()}}, this value controls the approximation of \code{x} used to identify potential intersections on \code{y}. The default value of 4 gives the best performance for most operations, but for specialized operations users may wish to use a higher value to increase performance.} } \value{ A vector of length \code{x}. } \description{ These functions are similar to accessors and predicates, but instead of recycling \code{x} and \code{y} to a common length and returning a vector of that length, these functions return a vector of length \code{x} with each element \code{i} containing information about how the entire vector \code{y} relates to the feature at \code{x[i]}. } \examples{ city_names <- c("Vatican City", "San Marino", "Luxembourg") cities <- s2_data_cities(city_names) country_names <- s2_data_tbl_countries$name countries <- s2_data_countries() # closest feature returns y indices of the closest feature # for each feature in x country_names[s2_closest_feature(cities, countries)] # farthest feature returns y indices of the farthest feature # for each feature in x country_names[s2_farthest_feature(cities, countries)] # use s2_closest_edges() to find the k-nearest neighbours nearest <- s2_closest_edges(cities, cities, k = 2, min_distance = 0) city_names city_names[unlist(nearest)] # predicate matrices country_names[s2_intersects_matrix(cities, countries)[[1]]] # distance matrices s2_distance_matrix(cities, cities) s2_max_distance_matrix(cities, countries[1:4]) } \seealso{ See pairwise predicate functions (e.g., \code{\link[=s2_intersects]{s2_intersects()}}). } s2/man/s2_cell_union_normalize.Rd0000644000175000017510000000302014737212474016614 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-cell-union.R \name{s2_cell_union_normalize} \alias{s2_cell_union_normalize} \alias{s2_cell_union_contains} \alias{s2_cell_union_intersects} \alias{s2_cell_union_intersection} \alias{s2_cell_union_union} \alias{s2_cell_union_difference} \alias{s2_covering_cell_ids} \alias{s2_covering_cell_ids_agg} \title{S2 cell union operators} \usage{ s2_cell_union_normalize(x) s2_cell_union_contains(x, y) s2_cell_union_intersects(x, y) s2_cell_union_intersection(x, y) s2_cell_union_union(x, y) s2_cell_union_difference(x, y) s2_covering_cell_ids( x, min_level = 0, max_level = 30, max_cells = 8, buffer = 0, interior = FALSE, radius = s2_earth_radius_meters() ) s2_covering_cell_ids_agg( x, min_level = 0, max_level = 30, max_cells = 8, buffer = 0, interior = FALSE, radius = s2_earth_radius_meters(), na.rm = FALSE ) } \arguments{ \item{x, y}{An \link[=as_s2_geography]{s2_geography} or \code{\link[=s2_cell_union]{s2_cell_union()}}.} \item{min_level, max_level}{The minimum and maximum levels to constrain the covering.} \item{max_cells}{The maximum number of cells in the covering. Defaults to 8.} \item{buffer}{A distance to buffer outside the geography} \item{interior}{Use \code{TRUE} to force the covering inside the geography.} \item{radius}{The radius to use (e.g., \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}})} \item{na.rm}{Remove NAs prior to computing aggregate?} } \description{ S2 cell union operators } s2/man/s2_geog_point.Rd0000644000175000017510000001176414737212474014555 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-constructors-formatters.R \name{s2_geog_point} \alias{s2_geog_point} \alias{s2_make_line} \alias{s2_make_polygon} \alias{s2_geog_from_text} \alias{s2_geog_from_wkb} \alias{s2_as_text} \alias{s2_as_binary} \alias{s2_tessellate_tol_default} \title{Create and Format Geography Vectors} \usage{ s2_geog_point(longitude, latitude) s2_make_line(longitude, latitude, feature_id = 1L) s2_make_polygon( longitude, latitude, feature_id = 1L, ring_id = 1L, oriented = FALSE, check = TRUE ) s2_geog_from_text( wkt_string, oriented = FALSE, check = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default() ) s2_geog_from_wkb( wkb_bytes, oriented = FALSE, check = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default() ) s2_as_text( x, precision = 16, trim = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default() ) s2_as_binary( x, endian = wk::wk_platform_endian(), planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default() ) s2_tessellate_tol_default() } \arguments{ \item{longitude, latitude}{Vectors of latitude and longitude} \item{feature_id, ring_id}{Vectors for which a change in sequential values indicates a new feature or ring. Use \code{\link[=factor]{factor()}} to convert from a character vector.} \item{oriented}{TRUE if polygon ring directions are known to be correct (i.e., exterior rings are defined counter clockwise and interior rings are defined clockwise).} \item{check}{Use \code{check = FALSE} to skip error on invalid geometries} \item{wkt_string}{Well-known text} \item{planar}{Use \code{TRUE} to force planar edges in import or export.} \item{tessellate_tol_m}{The maximum number of meters to that a point must be moved to satisfy the planar edge constraint.} \item{wkb_bytes}{A \code{list()} of \code{raw()}} \item{x}{An object that can be converted to an s2_geography vector} \item{precision}{The number of significant digits to export when writing well-known text. If \code{trim = FALSE}, the number of digits after the decimal place.} \item{trim}{Should trailing zeroes be included after the decimal place?} \item{endian}{The endian-ness of the well-known binary. See \code{\link[wk:deprecated]{wk::wkb_translate_wkb()}}.} } \description{ These functions create and export \link[=as_s2_geography]{geography vectors}. Unlike the BigQuery geography constructors, these functions do not sanitize invalid or redundant input using \code{\link[=s2_union]{s2_union()}}. Note that when creating polygons using \code{\link[=s2_make_polygon]{s2_make_polygon()}}, rings can be open or closed. } \examples{ # create point geographies using coordinate values: s2_geog_point(-64, 45) # create line geographies using coordinate values: s2_make_line(c(-64, 8), c(45, 71)) # optionally, separate features using feature_id: s2_make_line( c(-64, 8, -27, -27), c(45, 71, 0, 45), feature_id = c(1, 1, 2, 2) ) # create polygon geographies using coordinate values: # (rings can be open or closed) s2_make_polygon(c(-45, 8, 0), c(64, 71, 90)) # optionally, separate rings and/or features using # ring_id and/or feature_id s2_make_polygon( c(20, 10, 10, 30, 45, 30, 20, 20, 40, 20, 45), c(35, 30, 10, 5, 20, 20, 15, 25, 40, 45, 30), feature_id = c(rep(1, 8), rep(2, 3)), ring_id = c(1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1) ) # import and export well-known text (geog <- s2_geog_from_text("POINT (-64 45)")) s2_as_text(geog) # import and export well-known binary (geog <- s2_geog_from_wkb(wk::as_wkb("POINT (-64 45)"))) s2_as_binary(geog) # import geometry from planar space s2_geog_from_text( "POLYGON ((0 0, 1 0, 0 1, 0 0))", planar = TRUE, tessellate_tol_m = 1 ) # export geographies into planar space geog <- s2_make_polygon(c(179, -179, 179), c(10, 10, 11)) s2_as_text(geog, planar = TRUE) # polygons containing a pole need an extra step geog <- s2_data_countries("Antarctica") geom <- s2_as_text( s2_intersection(geog, s2_world_plate_carree()), planar = TRUE ) } \seealso{ See \code{\link[=as_s2_geography]{as_s2_geography()}} for other ways to construct geography vectors. BigQuery's geography function reference: \itemize{ \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogpoint}{ST_GEOGPOINT} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makeline}{ST_MAKELINE} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makepolygon}{ST_MAKEPOLYGON} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromtext}{ST_GEOGFROMTEXT} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromwkb}{ST_GEOGFROMWKB} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_astext}{ST_ASTEXT} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_asbinary}{ST_ASBINARY} } } s2/man/figures/0000755000175000017510000000000014737212474013163 5ustar nileshnileshs2/man/figures/rc300.png0000644000175000017510000003652614737212474014534 0ustar nileshnileshPNG  IHDR,D;sRGB pHYs.#.#x?viTXtXML:com.adobe.xmp Adobe ImageReady 1 ).=;$IDATx E;k& d!B!NC yB5O}$, "Ld\6$3dL2۽]wzٲ`fvuթSN:}jm{YΊى.~_ys\'Z Usy9PoߐA RVg,}[R7Y*eEiJV 3^g0Z1Oʯ~U.rȁ{W'뻮^$-u+XR9N1!m;n3o9ZJ͑r8Nj`0W /rȁ{/3RV˗?XNܗŃBAǯ 2]JR\+pQ٣P:&>.㤙;*hmsEW ʺ|ٳ nx7]3uܭt~Z;}A{Mdd 2Wrҝ'79Ac5E#(0S0ʾ6R9sPV9PAā= Z]%}æ' G8E7T^x/rȁ4hT )X}Rẫ\,{5u]Y^@JTۇ1Qȁ"0e~O ee碵e9Q9pppU"`MIΗX?p/dMwYel4>Hn2P!]o9|WZ_J)A"j%sǾԭ"eU=c[|7WZUI | jdRvTpX\u^MpêFhok)Nζm/|^pSڰ+rݶfVqY8Ӟ4 e#m&Na?:jTYZ{12ܯTU-Ͱ'irWE-˙Z__ߐ6*wpr*Dmm6F2ӦM+4iұGuFŅS7kh'u,:.F.e^MFte:ڻ&X:p7 vT%FTRC@AWeQSWW%\h]imIx vرUr؇Iill֑dNᅜZ%@sPsTC/suJz֕R RScOL +,VЀ) @!fNxXu5'IKX:-uE52EyEئNKp]tE K}ܸqDbd*;!^ٰaßB+,[SS3J1?%.8Nu`% KkeK$;#*˱>%A(/c,6?cٿb;TWѧe 4jngZ?GR).sMR::v"(WTT޽ctAk]{Ɓ:MA|7^6.;2UO'|K|OvhH-Jw|XHpIsGnݺ-ՓgɳByʉkljr]E>$n!JJlxqyN><3i'M=(a2ac~Iϫ7σY/{kӺN7@XzVc O`,e$7egm6^9qHUfRXm#ל/_qGYr.:L~^Њ9ݕ-el2qij@ہI+ayLCo(U]mĚ~ @`Fz'; AXo|/P'N|wBT~ ?h!OՈ+ƊG"LˉSDq?$?盔-?ޜxPk %Û^HKkj E (*x3Z<$ĿCÝFECOd<1 K*F.+?sYplyVHt& s9 RIy_3E8J%_# aUNxsĈ mjM$eUEk CnϦ6zM<9ưKC|RFxm8ʃпQgB_Fnl~Ws 3)gҹ\x}`<\P,yCs< GPQ//.ux՗(W}T|ΪoƣF,4 q6[6P"kjj.@(a`ueEEe34jZ*!MF %␐ʢ|>>)+[Y𥠜#UAc !tq܀ͭtRR]\ì̕ÖAّ(O/t_YeS=M&h%џL^Y_kϪ,ZE3qwҸϲJ |/^@k@|{.~Y.#:UN V=۹ūػΟT)N.NJKe:ΎxGpU^C'wei.QmQ:ɂҵ뙺wmzQ-zQpFQV)g)5ʺ}+ 3{Zp Τ!̤YPI}:1""HjjT+(4xؾwן9w=틡w6'*8ϯm%Mc)Tm]4V2h1N߼_'a2~ zD}%h.Ѥ |/O}CЬW-لY{E;aQ஧RdA%Lae]xltoAB<:RI]^B#!nS|I IƆX , &O/ey#Dr7cÐH$C< xC،<*彑gݥ3ׯ *VUv|5 %püy'4@Z;,3bFyif; 6 wylì%e 'eU*IGIEG^R۔K#Wb *9'ȃ>TJy@iifNN7\pzjWz#%:Hce3>$ ꣺3p>8 jh6<}ןΘ#1bi y g<' RN:+ai%\Y^ȉ7$5 1_5FKݲb]0DeG)3ϔ9ބN}EH6ԽSȩ\;S%3Ŵ>3NDaFcE}c„ zp_y\[V>l^Uȯg趽֎MR]C<]\MLsS)+uvf$JG_&JOf4É3܍ BhrNBZ;N3}ٙ\~BQIzیcԴn$#@9UptȾs}MuP' \r;Q~S0| Z6FN Rd@Q^,5PX)htN~A\ \عmlllrB%?m;ֲRy34?}x˵*%%>R|^a+ U׷[6]" $ߦzXM]f $,E\7WZ"$“/p_D*~)UZ#14o-~Ag5AEEsh .a%w1(x8Xq s~u4~͚Irj,RVHzIǜ[Zqhԍ*nntBƙB>gr]ዔdㆍK#^rF虅:F>IY%@F^ qXSSCB GR*N~/n ^-|F,5=;{>Li _TWmݛYnB ;0o~O) 3xx^%2׋d,Mes竊¹IU=ٳO?t%콣4ɘ{Oz9K&x_vГgN[gDѝF05l9ALxiw4#@ΈڡQ$VYQai6uΡUmW7mlTErbܚef-L~(4NklEEQ(X- РwcP7IiY(MC9t2ZaIv7FH,K@?IJĚLQ8ZQBpn&BQСEY`alnV+70$LlfD7qJh2NuV]M@[ދ9["eOJhr*րW<(mLWrघ  f5cmݺ5Ki'~ |~-H 2}~\*++1cnx*/&K޶c䊹bn97kb{uuRJp,|)CMMsXU`}3*c1ػw H8#eBc:8MG’ש0Qi"+0RF2V@􌔕cv7| >=ڔ2TXac {hxK"ˣbKU8QRmn|ZPZds*)_wRGKZ͈ ܬ"vrY!i(kko{`w6@xr: CCV㧸zѳ\į4Y!M+}Rc0ao3cR խ,lawǢhTR:4pRBª\4|ڀ{ule!L~H:H/-Țf۸_[T>ofZRRdΗ}?0˚5WS?awynv]{_xa8YaJMxEk؃nKt "_ҏR,)^$VDcf29#yeQ G016UTqTT&xY qee pzɯ ß^EHr#c aJ*Jw&JP\8I5\ WtZ)C]G& WKcv'Z5tNDpEܫ&kPߡ5~5ȸQ0I 4*EeXGlh }LςY os)t0^,!ڂf 1*}`< 7 ̱%+cQb.`֖W9缲2QY1t]g>Wm*T8x+Ӌϴ3w'۵+ñi`iAF>*03Ac12 xyXJp%}eއsQ\$tpvHPކ(>ec{qa-Je444`MJkqW/A NY%,T\FeƁ˅ r;%NJh-<+c%xNio볶B1DtzծsԱ;wnNGGݻw\#+-k?kH IY$q@cԭd8Wg~ᎋ7N9nUt\qQs{렰 -1akjIƭb0nӌ%߽伆gµ<V(,tPFط-O=3gvG H*Au)am:YT{Xv -4V_\H~vCD/17Kpt7ˬb|ŪJطV7jDJd-jOfx~ſcJk{ ]AB9$k L"FG-l᱉Ԡͺ%?f#o1@q ږUCn$g_;kb`XMWϠj7iS a+PDFfԜJ>œd62Ic 󜱺gy8 D/w(P' }0IL=ccϠW8}񛅣QjFoԨ緟hDJH!O%fA1NlM*$i2fPAJu&a̪~0NdMbV[ ӘnSN5- uI|jw xrgu5+f"ik Ѡ&5wCUa@F4M LZ!bVCwu@O횝#j:H,My<& Crʚ(p'M(cLK( #j˃x>C"5VCz-_HGxUsfN~ex#Qb.VFF(u^{gΠ-u\4QC؛j$`/)&}iӼ?oM":R`f6 pKHq8Uz ֭d4`~tZk}5N7s;+56iR|RV⩔%ea(E(뼓Hf)Яn8/F<OEn%kY|1Z9_F)<ה2Pm-^ (ecC*Zrjjj+{в[Iz;< !d-y?ZEx+/ªµH3 /O f>+Rox6X)gd4, GHmFy8 0!vO% 2݈ơ %ũ1N kY9 s(+}9ę߅%tqķFpItCt'M u&pAd? MP>Du;葆3Ն X4:(s9jWQ "%j&(ʡgX: oI)po{ ObwYtzڀ e~eįʗ+R7#?GidCQ޶AHȝ_͹fF4|G*'FuX;ke RrxJqK>BXkeb3M"A Clx _$=,m:=FX[0nc,}+n=c^呜Z"1J(<6;X0*[WƅMܦs>χWƙU6ሮO3o9t oGz574>|gwevYoƅ8.sѢEGki`Fk ⳌUqx7hFho#|SGù/Il*x`=Ğ B5xiow UFTiRz|!'"$8BD*x4!teA%X1rDw}*JZH%bM~S(g#D">)<dz e>`P*z hx*mSX'|v]8_ Xީ^ <@>Zc䃛4Z#NK-Ӊɋ2ކB^: w-p mq_cڴŗz3 y :+J@J[+DK*,wنv ƪǼ; ?9xTVGAtNsݔ .8]WS c}Q߹P٤6/g^т6ܕ\ĜjsKB>C J'۾&uӌaqYD[0ƈNNEIuJQ^3x|(1hV"\JZ]8z d{16,e ngYh4l"ϣPHKFPn\? ĝ8n֦/%op2PQ#p6G>@0)Zxw!҄}7`&!C9Eצ M'T](0n{eidpk Ƅ^g= oєG<!{f*8l)/m6.FRhLe67[(*)y.fYI9Gў:n'\.N+y7ϓ8'8$!mCNT1"z R[Y7/_M !::㛉VYՕ)$ݍ6],K]9g TB..f@k fxJUP8~P|jTd,l wi{>1QF@_ɥ {+-_Ќ࢟?U|DՐ)#R[ ^Ga/=N}92ZT<*DDX\Ƚ]J)5g׽ npW|DO~`(+՗+=ϻ|JCv;keUDk'EyK[ڝe ?a_)@m(PaVxp9P@}Z4XKl)E9pqpґ ~nߗvTB46jYkd|V1UOt$M+z%FtŷbxEB)d di,- ˇ)>9PAˁ֠ThLИ@֦ut&֐0THtGμijIw.i";ph)3]&Op &?i^m'w<&X[򴛪!*Sl~-F9PߝTJ -"Q6Ǭ8aOd W)kmn9pK }8mV;(a-9'Q2NSjhñ4tp B0鎹V /9ps`,,,;|m;_J{42qĦ/cZjs=EʪceƎG/P_ PVfay|3 PtE9@A/y WF)c3ԘPE2?we'z w;،=і( }N5 F+jjߖȁ":€z9|YPv+aU+Zf kjϳrcyY{7b 7<|\xBc_£ :_-r w=/]E9g +b8~ pI*(ͱV}̌#}EyIݢ/>갔Ύ6:tiNP,^XVφ:cV%l͉ґ.q)NKynҊE*r{@ĉ(kgɶm2_aYFę˷q(Ϲofjk='{wkgE#ۻsf\CV^JO=۱Vh¢{6۾TN OEl1,)M+f?ӻ%h>rl:O]w=$@RSEb&?QVW ,rȁ{faٵVX=VY+s,kfP~ڒRs9TGVaeLT3u*hrW{YnNEY$ʪNJaE.8G ܬ)dDvP3Ja# sm{՞"HKN++rȁ{ga(Y:Ұg_vYSfv}BھmK?sfUW]է#P o4ŧ"89QhdIENDB`s2/man/s2_data_tbl_countries.Rd0000644000175000017510000000261314737212474016261 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{s2_data_tbl_countries} \alias{s2_data_tbl_countries} \alias{s2_data_tbl_timezones} \alias{s2_data_tbl_cities} \alias{s2_data_countries} \alias{s2_data_timezones} \alias{s2_data_cities} \title{Low-resolution world boundaries, timezones, and cities} \format{ A data.frame with columns \code{name} (character), and \code{geometry} (wk_wkb) An object of class \code{data.frame} with 120 rows and 2 columns. An object of class \code{data.frame} with 243 rows and 3 columns. } \source{ \href{https://www.naturalearthdata.com/}{Natural Earth Data} } \usage{ s2_data_tbl_countries s2_data_tbl_timezones s2_data_tbl_cities s2_data_countries(name = NULL) s2_data_timezones(utc_offset_min = NULL, utc_offset_max = utc_offset_min) s2_data_cities(name = NULL) } \arguments{ \item{name}{The name of a country, continent, city, or \code{NULL} for all features.} \item{utc_offset_min, utc_offset_max}{Minimum and/or maximum timezone offsets.} } \description{ Well-known binary versions of the \href{https://www.naturalearthdata.com/}{Natural Earth} low-resolution world boundaries and timezone boundaries. } \examples{ head(s2_data_countries()) s2_data_countries("Germany") s2_data_countries("Europe") head(s2_data_timezones()) s2_data_timezones(-4) head(s2_data_cities()) s2_data_cities("Cairo") } \keyword{datasets} s2/man/s2_point.Rd0000644000175000017510000000163214737212474013545 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-point.R \name{s2_point} \alias{s2_point} \alias{s2_point_crs} \alias{as_s2_point} \alias{as_s2_point.default} \alias{as_s2_point.wk_xy} \alias{as_s2_point.wk_xyz} \title{Create an S2 Point Vector} \usage{ s2_point(x, y, z) s2_point_crs() as_s2_point(x, ...) \method{as_s2_point}{default}(x, ...) \method{as_s2_point}{wk_xy}(x, ...) \method{as_s2_point}{wk_xyz}(x, ...) } \arguments{ \item{x, y, z}{Vectors of latitude and longitude values in degrees.} \item{...}{Unused} } \value{ An object with class s2_point } \description{ In S2 terminology, a "point" is a 3-dimensional unit vector representation of an \code{\link[=s2_point]{s2_point()}}. Internally, all s2 objects are stored as 3-dimensional unit vectors. } \examples{ point <- s2_lnglat(-64, 45) # Halifax, Nova Scotia! as_s2_point(point) as.data.frame(as_s2_point(point)) } s2/man/s2_contains.Rd0000644000175000017510000001243214737212474014232 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-predicates.R \name{s2_contains} \alias{s2_contains} \alias{s2_within} \alias{s2_covered_by} \alias{s2_covers} \alias{s2_disjoint} \alias{s2_intersects} \alias{s2_equals} \alias{s2_intersects_box} \alias{s2_touches} \alias{s2_dwithin} \alias{s2_prepared_dwithin} \title{S2 Geography Predicates} \usage{ s2_contains(x, y, options = s2_options(model = "open")) s2_within(x, y, options = s2_options(model = "open")) s2_covered_by(x, y, options = s2_options(model = "closed")) s2_covers(x, y, options = s2_options(model = "closed")) s2_disjoint(x, y, options = s2_options()) s2_intersects(x, y, options = s2_options()) s2_equals(x, y, options = s2_options()) s2_intersects_box( x, lng1, lat1, lng2, lat2, detail = 1000, options = s2_options() ) s2_touches(x, y, options = s2_options()) s2_dwithin(x, y, distance, radius = s2_earth_radius_meters()) s2_prepared_dwithin(x, y, distance, radius = s2_earth_radius_meters()) } \arguments{ \item{x, y}{\link[=as_s2_geography]{geography vectors}. These inputs are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects (e.g., character vectors of well-known text) directly.} \item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline model to use and the snap level.} \item{lng1, lat1, lng2, lat2}{A latitude/longitude range} \item{detail}{The number of points with which to approximate non-geodesic edges.} \item{distance}{A distance on the surface of the earth in the same units as \code{radius}.} \item{radius}{Radius of the earth. Defaults to the average radius of the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.} } \description{ These functions operate two geography vectors (pairwise), and return a logical vector. } \section{Model}{ The geometry model indicates whether or not a geometry includes its boundaries. Boundaries of line geometries are its end points. OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries (\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons do not overlap or two lines do not cross, no point exist that belong to more than one of the geometries. (This latter form, half-closed, is not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open) and covers/covered_by (closed) correspond to the SFA standard specification of these operators. } \examples{ s2_contains( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_within( c("POINT (5 5)", "POINT (-1 1)"), "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))" ) s2_covered_by( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_covers( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_disjoint( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_intersects( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_equals( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0))", "POLYGON ((-1 -1, 10 0, 10 10, 0 10, -1 -1))" ) ) s2_intersects( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)") ) s2_intersects_box( c("POINT (5 5)", "POINT (-1 1)"), 0, 0, 10, 10 ) s2_touches( "POLYGON ((0 0, 0 1, 1 1, 0 0))", c("POINT (0 0)", "POINT (0.5 0.75)", "POINT (0 0.5)") ) s2_dwithin( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)"), 0 # distance in meters ) s2_dwithin( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", c("POINT (5 5)", "POINT (-1 1)"), 1e6 # distance in meters ) } \seealso{ Matrix versions of these predicates (e.g., \code{\link[=s2_intersects_matrix]{s2_intersects_matrix()}}). BigQuery's geography function reference: \itemize{ \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_contains}{ST_CONTAINS} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_coveredby}{ST_COVEREDBY} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_covers}{ST_COVERS} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_disjoint}{ST_DISJOINT} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_equals}{ST_EQUALS} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersects}{ST_INTERSECTS} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersectsbox}{ST_INTERSECTSBOX} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_touches}{ST_TOUCHES} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_within}{ST_WITHIN} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dwithin}{ST_DWITHIN} } } s2/man/s2_boundary.Rd0000644000175000017510000001623714737212474014246 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-transformers.R \name{s2_boundary} \alias{s2_boundary} \alias{s2_centroid} \alias{s2_closest_point} \alias{s2_minimum_clearance_line_between} \alias{s2_difference} \alias{s2_sym_difference} \alias{s2_intersection} \alias{s2_union} \alias{s2_snap_to_grid} \alias{s2_simplify} \alias{s2_rebuild} \alias{s2_buffer_cells} \alias{s2_convex_hull} \alias{s2_centroid_agg} \alias{s2_coverage_union_agg} \alias{s2_rebuild_agg} \alias{s2_union_agg} \alias{s2_convex_hull_agg} \alias{s2_point_on_surface} \title{S2 Geography Transformations} \usage{ s2_boundary(x) s2_centroid(x) s2_closest_point(x, y) s2_minimum_clearance_line_between(x, y) s2_difference(x, y, options = s2_options()) s2_sym_difference(x, y, options = s2_options()) s2_intersection(x, y, options = s2_options()) s2_union(x, y = NULL, options = s2_options()) s2_snap_to_grid(x, grid_size) s2_simplify(x, tolerance, radius = s2_earth_radius_meters()) s2_rebuild(x, options = s2_options()) s2_buffer_cells( x, distance, max_cells = 1000, min_level = -1, radius = s2_earth_radius_meters() ) s2_convex_hull(x) s2_centroid_agg(x, na.rm = FALSE) s2_coverage_union_agg(x, options = s2_options(), na.rm = FALSE) s2_rebuild_agg(x, options = s2_options(), na.rm = FALSE) s2_union_agg(x, options = s2_options(), na.rm = FALSE) s2_convex_hull_agg(x, na.rm = FALSE) s2_point_on_surface(x, na.rm = FALSE) } \arguments{ \item{x, y}{\link[=as_s2_geography]{geography vectors}. These inputs are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects (e.g., character vectors of well-known text) directly.} \item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline model to use and the snap level.} \item{grid_size}{The grid size to which coordinates should be snapped; will be rounded to the nearest power of 10.} \item{tolerance}{The minimum distance between vertexes to use when simplifying a geography.} \item{radius}{Radius of the earth. Defaults to the average radius of the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.} \item{distance}{The distance to buffer, in units of \code{radius}.} \item{max_cells}{The maximum number of cells to approximate a buffer.} \item{min_level}{The minimum cell level used to approximate a buffer (1 - 30). Setting this value too high will result in unnecessarily large geographies, but may help improve buffers along long, narrow regions.} \item{na.rm}{For aggregate calculations use \code{na.rm = TRUE} to drop missing values.} } \description{ These functions operate on one or more geography vectors and return a geography vector. } \section{Model}{ The geometry model indicates whether or not a geometry includes its boundaries. Boundaries of line geometries are its end points. OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries (\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons do not overlap or two lines do not cross, no point exist that belong to more than one of the geometries. (This latter form, half-closed, is not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open) and covers/covered_by (closed) correspond to the SFA standard specification of these operators. } \examples{ # returns the boundary: # empty for point, endpoints of a linestring, # perimeter of a polygon s2_boundary("POINT (-64 45)") s2_boundary("LINESTRING (0 0, 10 0)") s2_boundary("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") # returns the area-weighted centroid, element-wise s2_centroid("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") s2_centroid("LINESTRING (0 0, 10 0)") # s2_point_on_surface guarantees a point on surface # Note: this is not the same as st_point_on_surface s2_centroid("POLYGON ((0 0, 10 0, 1 1, 0 10, 0 0))") s2_point_on_surface("POLYGON ((0 0, 10 0, 1 1, 0 10, 0 0))") # returns the unweighted centroid of the entire input s2_centroid_agg(c("POINT (0 0)", "POINT (10 0)")) # returns the closest point on x to y s2_closest_point( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT (0 90)" # north pole! ) # returns the shortest possible line between x and y s2_minimum_clearance_line_between( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT (0 90)" # north pole! ) # binary operations: difference, symmetric difference, intersection and union s2_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", # 32 bit platforms may need to set snap rounding s2_options(snap = s2_snap_level(30)) ) s2_sym_difference( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", # 32 bit platforms may need to set snap rounding s2_options(snap = s2_snap_level(30)) ) s2_intersection( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", # 32 bit platforms may need to set snap rounding s2_options(snap = s2_snap_level(30)) ) s2_union( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", # 32 bit platforms may need to set snap rounding s2_options(snap = s2_snap_level(30)) ) # s2_convex_hull_agg builds the convex hull of a list of geometries s2_convex_hull_agg( c( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ) ) # use s2_union_agg() to aggregate geographies in a vector s2_coverage_union_agg( c( "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ), # 32 bit platforms may need to set snap rounding s2_options(snap = s2_snap_level(30)) ) # snap to grid rounds coordinates to a specified grid size s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2) } \seealso{ BigQuery's geography function reference: \itemize{ \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_boundary}{ST_BOUNDARY} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_centroid}{ST_CENTROID} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_closestpoint}{ST_CLOSESTPOINT} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_difference}{ST_DIFFERENCE} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersection}{ST_INTERSECTION} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union}{ST_UNION} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_snaptogrid}{ST_SNAPTOGRID} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_simplify}{ST_SIMPLIFY} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union_agg}{ST_UNION_AGG} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#s2_centroid_agg}{ST_CENTROID_AGG} } } s2/man/s2_options.Rd0000644000175000017510000000776114737212474014120 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-options.R \name{s2_options} \alias{s2_options} \alias{s2_snap_identity} \alias{s2_snap_level} \alias{s2_snap_precision} \alias{s2_snap_distance} \title{Geography Operation Options} \usage{ s2_options( model = NULL, snap = s2_snap_identity(), snap_radius = -1, duplicate_edges = FALSE, edge_type = "directed", validate = FALSE, polyline_type = "path", polyline_sibling_pairs = "keep", simplify_edge_chains = FALSE, split_crossing_edges = FALSE, idempotent = FALSE, dimensions = c("point", "polyline", "polygon") ) s2_snap_identity() s2_snap_level(level) s2_snap_precision(precision) s2_snap_distance(distance) } \arguments{ \item{model}{One of 'open', 'semi-open' (default for polygons), or 'closed' (default for polylines). See section 'Model'} \item{snap}{Use \code{s2_snap_identity()}, \code{s2_snap_distance()}, \code{s2_snap_level()}, or \code{s2_snap_precision()} to specify how or if coordinate rounding should occur.} \item{snap_radius}{As opposed to the snap function, which specifies the maximum distance a vertex should move, the snap radius (in radians) sets the minimum distance between vertices of the output that don't cause vertices to move more than the distance specified by the snap function. This can be used to simplify the result of a boolean operation. Use -1 to specify that any minimum distance is acceptable.} \item{duplicate_edges}{Use \code{TRUE} to keep duplicate edges (e.g., duplicate points).} \item{edge_type}{One of 'directed' (default) or 'undirected'.} \item{validate}{Use \code{TRUE} to validate the result from the builder.} \item{polyline_type}{One of 'path' (default) or 'walk'. If 'walk', polylines that backtrack are preserved.} \item{polyline_sibling_pairs}{One of 'discard' (default) or 'keep'.} \item{simplify_edge_chains}{Use \code{TRUE} to remove vertices that are within \code{snap_radius} of the original vertex.} \item{split_crossing_edges}{Use \code{TRUE} to split crossing polyline edges when creating geometries.} \item{idempotent}{Use \code{FALSE} to apply snap even if snapping is not necessary to satisfy vertex constraints.} \item{dimensions}{A combination of 'point', 'polyline', and/or 'polygon' that can used to constrain the output of \code{\link[=s2_rebuild]{s2_rebuild()}} or a boolean operation.} \item{level}{A value from 0 to 30 corresponding to the cell level at which snapping should occur.} \item{precision}{A number by which coordinates should be multiplied before being rounded. Rounded to the nearest exponent of 10.} \item{distance}{A distance (in radians) denoting the maximum distance a vertex should move in the snapping process.} } \description{ These functions specify defaults for options used to perform operations and construct geometries. These are used in predicates (e.g., \code{\link[=s2_intersects]{s2_intersects()}}), and boolean operations (e.g., \code{\link[=s2_intersection]{s2_intersection()}}) to specify the model for containment and how new geometries should be constructed. } \section{Model}{ The geometry model indicates whether or not a geometry includes its boundaries. Boundaries of line geometries are its end points. OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries (\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons do not overlap or two lines do not cross, no point exist that belong to more than one of the geometries. (This latter form, half-closed, is not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open) and covers/covered_by (closed) correspond to the SFA standard specification of these operators. } \examples{ # use s2_options() to specify containment models, snap level # layer creation options, and builder options s2_options(model = "closed", snap = s2_snap_level(30)) } s2/man/s2_cell_union.Rd0000644000175000017510000000144614737212474014546 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-cell-union.R \name{s2_cell_union} \alias{s2_cell_union} \alias{as_s2_geography.s2_cell_union} \alias{as_s2_cell_union} \alias{as_s2_cell_union.s2_cell_union} \alias{as_s2_cell_union.s2_cell} \alias{as_s2_cell_union.character} \title{Create S2 Cell Union vectors} \usage{ s2_cell_union(x = list()) \method{as_s2_geography}{s2_cell_union}(x, ...) as_s2_cell_union(x, ...) \method{as_s2_cell_union}{s2_cell_union}(x, ...) \method{as_s2_cell_union}{s2_cell}(x, ...) \method{as_s2_cell_union}{character}(x, ...) } \arguments{ \item{x}{A \code{list()} of \code{\link[=s2_cell]{s2_cell()}} vectors.} \item{...}{Passed to S3 methods} } \value{ An object of class "s2_cell_union". } \description{ Create S2 Cell Union vectors } s2/man/s2_bounds_cap.Rd0000644000175000017510000000265314737212474014535 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-bounds.R \name{s2_bounds_cap} \alias{s2_bounds_cap} \alias{s2_bounds_rect} \title{Compute feature-wise and aggregate bounds} \usage{ s2_bounds_cap(x) s2_bounds_rect(x) } \arguments{ \item{x}{An \code{\link[=s2_geography]{s2_geography()}} vector.} } \value{ Both functions return a \code{data.frame}: \itemize{ \item \code{\link[=s2_bounds_rect]{s2_bounds_rect()}}: Columns \code{minlng}, \code{minlat}, \code{maxlng}, \code{maxlat} (degrees) \item \code{\link[=s2_bounds_cap]{s2_bounds_cap()}}: Columns \code{lng}, \code{lat}, \code{angle} (degrees) } } \description{ \code{\link[=s2_bounds_rect]{s2_bounds_rect()}} returns a bounding latitude-longitude rectangle that contains the region; \code{\link[=s2_bounds_cap]{s2_bounds_cap()}} returns a bounding circle represented by a centre point (lat, lng) and an angle. The bound may not be tight for points, polylines and geometry collections. The rectangle returned may depend on the order of points or polylines. \code{lng_lo} values larger than \code{lng_hi} indicate regions that span the antimeridian, see the Fiji example. } \examples{ s2_bounds_cap(s2_data_countries("Antarctica")) s2_bounds_cap(s2_data_countries("Netherlands")) s2_bounds_cap(s2_data_countries("Fiji")) s2_bounds_rect(s2_data_countries("Antarctica")) s2_bounds_rect(s2_data_countries("Netherlands")) s2_bounds_rect(s2_data_countries("Fiji")) } s2/man/s2_lnglat.Rd0000644000175000017510000000174214737212474013677 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-lnglat.R \name{s2_lnglat} \alias{s2_lnglat} \alias{as_s2_lnglat} \alias{as_s2_lnglat.default} \alias{as_s2_lnglat.wk_xy} \alias{as_s2_lnglat.wk_xyz} \title{Create an S2 LngLat Vector} \usage{ s2_lnglat(lng, lat) as_s2_lnglat(x, ...) \method{as_s2_lnglat}{default}(x, ...) \method{as_s2_lnglat}{wk_xy}(x, ...) \method{as_s2_lnglat}{wk_xyz}(x, ...) } \arguments{ \item{lat, lng}{Vectors of latitude and longitude values in degrees.} \item{x}{A \code{\link[=s2_lnglat]{s2_lnglat()}} vector or an object that can be coerced to one.} \item{...}{Unused} } \value{ An object with class s2_lnglat } \description{ This class represents a latitude and longitude on the Earth's surface. Most calculations in S2 convert this to a \code{\link[=as_s2_point]{as_s2_point()}}, which is a unit vector representation of this value. } \examples{ s2_lnglat(45, -64) # Halifax, Nova Scotia! as.data.frame(s2_lnglat(45, -64)) } s2/man/as_s2_geography.Rd0000644000175000017510000000500014737212474015055 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-geography.R \name{as_s2_geography} \alias{as_s2_geography} \alias{s2_geography} \alias{as_s2_geography.s2_geography} \alias{as_s2_geography.wk_xy} \alias{as_s2_geography.wk_wkb} \alias{as_s2_geography.WKB} \alias{as_s2_geography.blob} \alias{as_s2_geography.wk_wkt} \alias{as_s2_geography.character} \alias{as_s2_geography.logical} \alias{as_wkb.s2_geography} \alias{as_wkt.s2_geography} \title{Create an S2 Geography Vector} \usage{ as_s2_geography(x, ...) s2_geography() \method{as_s2_geography}{s2_geography}(x, ...) \method{as_s2_geography}{wk_xy}(x, ...) \method{as_s2_geography}{wk_wkb}(x, ..., oriented = FALSE, check = TRUE) \method{as_s2_geography}{WKB}(x, ..., oriented = FALSE, check = TRUE) \method{as_s2_geography}{blob}(x, ..., oriented = FALSE, check = TRUE) \method{as_s2_geography}{wk_wkt}(x, ..., oriented = FALSE, check = TRUE) \method{as_s2_geography}{character}(x, ..., oriented = FALSE, check = TRUE) \method{as_s2_geography}{logical}(x, ...) \method{as_wkb}{s2_geography}(x, ...) \method{as_wkt}{s2_geography}(x, ...) } \arguments{ \item{x}{An object that can be converted to an s2_geography vector} \item{...}{Unused} \item{oriented}{TRUE if polygon ring directions are known to be correct (i.e., exterior rings are defined counter clockwise and interior rings are defined clockwise).} \item{check}{Use \code{check = FALSE} to skip error on invalid geometries} } \value{ An object with class s2_geography } \description{ Geography vectors are arrays of points, lines, polygons, and/or collections of these. Geography vectors assume coordinates are longitude and latitude on a perfect sphere. } \details{ The coercion function \code{\link[=as_s2_geography]{as_s2_geography()}} is used to wrap the input of most functions in the s2 package so that you can use other objects with an unambiguious interpretation as a geography vector. Geography vectors have a minimal \link[vctrs:vctrs-package]{vctrs} implementation, so you can use these objects in tibble, dplyr, and other packages that use the vctrs framework. } \seealso{ \code{\link[=s2_geog_from_wkb]{s2_geog_from_wkb()}}, \code{\link[=s2_geog_from_text]{s2_geog_from_text()}}, \code{\link[=s2_geog_point]{s2_geog_point()}}, \code{\link[=s2_make_line]{s2_make_line()}}, \code{\link[=s2_make_polygon]{s2_make_polygon()}} for other ways to create geography vectors, and \code{\link[=s2_as_binary]{s2_as_binary()}} and \code{\link[=s2_as_text]{s2_as_text()}} for other ways to export them. } s2/man/wk_handle.s2_geography.Rd0000644000175000017510000000512014737212474016330 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/wk-utils.R \name{wk_handle.s2_geography} \alias{wk_handle.s2_geography} \alias{s2_geography_writer} \alias{wk_writer.s2_geography} \alias{s2_trans_point} \alias{s2_trans_lnglat} \alias{s2_projection_plate_carree} \alias{s2_projection_mercator} \alias{s2_hemisphere} \alias{s2_world_plate_carree} \alias{s2_projection_orthographic} \title{Low-level wk filters and handlers} \usage{ \method{wk_handle}{s2_geography}( handleable, handler, ..., s2_projection = s2_projection_plate_carree(), s2_tessellate_tol = Inf ) s2_geography_writer( oriented = FALSE, check = TRUE, projection = s2_projection_plate_carree(), tessellate_tol = Inf ) \method{wk_writer}{s2_geography}(handleable, ...) s2_trans_point() s2_trans_lnglat() s2_projection_plate_carree(x_scale = 180) s2_projection_mercator(x_scale = 20037508.3427892) s2_hemisphere(centre) s2_world_plate_carree(epsilon_east_west = 0, epsilon_north_south = 0) s2_projection_orthographic(centre = s2_lnglat(0, 0)) } \arguments{ \item{handleable}{A geometry vector (e.g., \code{\link[wk:wkb]{wkb()}}, \code{\link[wk:wkt]{wkt()}}, \code{\link[wk:xy]{xy()}}, \code{\link[wk:rct]{rct()}}, or \code{\link[sf:sfc]{sf::st_sfc()}}) for which \code{\link[wk:wk_handle]{wk_handle()}} is defined.} \item{handler}{A \link[wk:wk_handle]{wk_handler} object.} \item{...}{Passed to the \code{\link[wk:wk_handle]{wk_handle()}} method.} \item{oriented}{TRUE if polygon ring directions are known to be correct (i.e., exterior rings are defined counter clockwise and interior rings are defined clockwise).} \item{check}{Use \code{check = FALSE} to skip error on invalid geometries} \item{projection, s2_projection}{One of \code{\link[=s2_projection_plate_carree]{s2_projection_plate_carree()}} or \code{\link[=s2_projection_mercator]{s2_projection_mercator()}}} \item{tessellate_tol, s2_tessellate_tol}{An angle in radians. Points will not be added if a line segment is within this distance of a point.} \item{x_scale}{The maximum x value of the projection} \item{centre}{The center point of the orthographic projection} \item{epsilon_east_west, epsilon_north_south}{Use a positive number to define the edges of a Cartesian world slightly inward from -180, -90, 180, 90. This may be used to define a world outline for a projection where projecting at the extreme edges of the earth results in a non-finite value.} } \value{ \itemize{ \item \code{s2_projection_plate_carree()}, \code{s2_projection_mercator()}: An external pointer to an S2 projection. } } \description{ Low-level wk filters and handlers } s2/man/s2_earth_radius_meters.Rd0000644000175000017510000000142314737212474016443 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-earth.R \name{s2_earth_radius_meters} \alias{s2_earth_radius_meters} \title{Earth Constants} \usage{ s2_earth_radius_meters() } \description{ According to Yoder (1995), the radius of the earth is 6371.01 km. These functions are used to set the default radis for functions that return a distance or accept a distance as input (e.g., \code{\link[=s2_distance]{s2_distance()}} and \code{\link[=s2_dwithin]{s2_dwithin()}}). } \examples{ s2_earth_radius_meters() } \references{ Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the Solar System" in Global Earth Physics, A Handbook of Physical Constants, AGU Reference Shelf 1, American Geophysical Union, Table 2. \doi{10.1029/RF001p0001} } s2/man/s2_plot.Rd0000644000175000017510000000256314737212474013376 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot.R \name{s2_plot} \alias{s2_plot} \title{Plot S2 Geographies} \usage{ s2_plot( x, ..., asp = 1, xlab = "", ylab = "", rule = "evenodd", add = FALSE, plot_hemisphere = FALSE, simplify = TRUE, centre = NULL ) } \arguments{ \item{x}{A \code{\link[wk:wkb]{wkb()}} or \code{\link[wk:wkt]{wkt()}}} \item{...}{Passed to plotting functions for features: \code{\link[graphics:points]{graphics::points()}} for point and multipoint geometries, \code{\link[graphics:lines]{graphics::lines()}} for linestring and multilinestring geometries, and \code{\link[graphics:polypath]{graphics::polypath()}} for polygon and multipolygon geometries.} \item{asp, xlab, ylab}{Passed to \code{\link[graphics:plot.default]{graphics::plot()}}} \item{rule}{The rule to use for filling polygons (see \code{\link[graphics:polypath]{graphics::polypath()}})} \item{add}{Should a new plot be created, or should \code{handleable} be added to the existing plot?} \item{plot_hemisphere}{Plot the outline of the earth} \item{simplify}{Use \code{FALSE} to skip the simplification step} \item{centre}{The longitude/latitude point of the centre of the orthographic projection} } \value{ The input, invisibly } \description{ Plot S2 Geographies } \examples{ s2_plot(s2_data_countries()) s2_plot(s2_data_cities(), add = TRUE) } s2/man/s2_interpolate.Rd0000644000175000017510000000332114737212474014737 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-accessors.R, R/s2-transformers.R \name{s2_project} \alias{s2_project} \alias{s2_project_normalized} \alias{s2_interpolate} \alias{s2_interpolate_normalized} \title{Linear referencing} \usage{ s2_project(x, y, radius = s2_earth_radius_meters()) s2_project_normalized(x, y) s2_interpolate(x, distance, radius = s2_earth_radius_meters()) s2_interpolate_normalized(x, distance_normalized) } \arguments{ \item{x}{A simple polyline geography vector} \item{y}{A simple point geography vector. The point will be snapped to the nearest point on \code{x} for the purposes of interpolation.} \item{radius}{Radius of the earth. Defaults to the average radius of the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.} \item{distance}{A distance along \code{x} in \code{radius} units.} \item{distance_normalized}{A \code{distance} normalized to \code{\link[=s2_length]{s2_length()}} of \code{x}.} } \value{ \itemize{ \item \code{s2_interpolate()} returns the point on \code{x}, \code{distance} meters along the line. \item \code{s2_interpolate_normalized()} returns the point on \code{x} interpolated to a fraction along the line. \item \code{s2_project()} returns the \code{distance} that \code{point} occurs along \code{x}. \item \code{s2_project_normalized()} returns the \code{distance_normalized} along \code{x} where \code{point} occurs. } } \description{ Linear referencing } \examples{ s2_project_normalized("LINESTRING (0 0, 0 90)", "POINT (0 22.5)") s2_project("LINESTRING (0 0, 0 90)", "POINT (0 22.5)") s2_interpolate_normalized("LINESTRING (0 0, 0 90)", 0.25) s2_interpolate("LINESTRING (0 0, 0 90)", 2501890) } s2/man/s2-package.Rd0000644000175000017510000000256614737212474013734 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-package.R \docType{package} \name{s2-package} \alias{s2} \alias{s2-package} \title{s2: Spherical Geometry Operators Using the S2 Geometry Library} \description{ Provides R bindings for Google's s2 library for geometric calculations on the sphere. High-performance constructors and exporters provide high compatibility with existing spatial packages, transformers construct new geometries from existing geometries, predicates provide a means to select geometries based on spatial relationships, and accessors extract information about geometries. } \seealso{ Useful links: \itemize{ \item \url{https://r-spatial.github.io/s2/} \item \url{https://github.com/r-spatial/s2} \item \url{http://s2geometry.io/} \item Report bugs at \url{https://github.com/r-spatial/s2/issues} } } \author{ \strong{Maintainer}: Edzer Pebesma \email{edzer.pebesma@uni-muenster.de} (\href{https://orcid.org/0000-0001-8049-7069}{ORCID}) Authors: \itemize{ \item Dewey Dunnington \email{dewey@fishandwhistle.net} (\href{https://orcid.org/0000-0002-9415-4582}{ORCID}) \item Ege Rubak \email{rubak@math.aau.dk} } Other contributors: \itemize{ \item Jeroen Ooms \email{jeroen.ooms@stat.ucla.edu} (configure script) [contributor] \item Google, Inc. (Original s2geometry.io source code) [copyright holder] } } \keyword{internal} s2/man/s2_is_collection.Rd0000644000175000017510000000742514737212474015250 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-accessors.R \name{s2_is_collection} \alias{s2_is_collection} \alias{s2_is_valid} \alias{s2_is_valid_detail} \alias{s2_dimension} \alias{s2_num_points} \alias{s2_is_empty} \alias{s2_area} \alias{s2_length} \alias{s2_perimeter} \alias{s2_x} \alias{s2_y} \alias{s2_distance} \alias{s2_max_distance} \title{S2 Geography Accessors} \usage{ s2_is_collection(x) s2_is_valid(x) s2_is_valid_detail(x) s2_dimension(x) s2_num_points(x) s2_is_empty(x) s2_area(x, radius = s2_earth_radius_meters()) s2_length(x, radius = s2_earth_radius_meters()) s2_perimeter(x, radius = s2_earth_radius_meters()) s2_x(x) s2_y(x) s2_distance(x, y, radius = s2_earth_radius_meters()) s2_max_distance(x, y, radius = s2_earth_radius_meters()) } \arguments{ \item{x, y}{\link[=as_s2_geography]{geography vectors}. These inputs are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects (e.g., character vectors of well-known text) directly.} \item{radius}{Radius of the earth. Defaults to the average radius of the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.} } \description{ Accessors extract information about \link[=as_s2_geography]{geography vectors}. } \examples{ # s2_is_collection() tests for multiple geometries in one feature s2_is_collection(c("POINT (-64 45)", "MULTIPOINT ((-64 45), (8 72))")) # s2_dimension() returns 0 for point, 1 for line, 2 for polygon s2_dimension( c( "GEOMETRYCOLLECTION EMPTY", "POINT (-64 45)", "LINESTRING (-64 45, 8 72)", "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", "GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 8 72))" ) ) # s2_num_points() counts points s2_num_points(c("POINT (-64 45)", "LINESTRING (-64 45, 8 72)")) # s2_is_empty tests for emptiness s2_is_empty(c("POINT (-64 45)", "POINT EMPTY")) # calculate area, length, and perimeter s2_area("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))") s2_perimeter("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))") s2_length(s2_boundary("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")) # extract x and y coordinates from points s2_x(c("POINT (-64 45)", "POINT EMPTY")) s2_y(c("POINT (-64 45)", "POINT EMPTY")) # calculate minimum and maximum distance between two geometries s2_distance( "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", "POINT (-64 45)" ) s2_max_distance( "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", "POINT (-64 45)" ) } \seealso{ BigQuery's geography function reference: \itemize{ \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_iscollection}{ST_ISCOLLECTION} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dimension}{ST_DIMENSION} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_numpoints}{ST_NUMPOINTS} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_isempty}{ST_ISEMPTY} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area}{ST_AREA} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_length}{ST_LENGTH} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_perimeter}{ST_PERIMETER} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_x}{ST_X} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_y}{ST_Y} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_distance}{ST_DISTANCE} \item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_maxdistance}{ST_MAXDISTANCE} } } s2/man/s2_data_example_wkt.Rd0000644000175000017510000000063714737212474015731 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{s2_data_example_wkt} \alias{s2_data_example_wkt} \title{Example Geometries} \format{ An object of class \code{list} of length 29. } \usage{ s2_data_example_wkt } \description{ These geometries are toy examples useful for testing various coordinate shuffling operations in the s2 package. } \keyword{datasets} s2/man/s2_cell_is_valid.Rd0000644000175000017510000000330514737212474015204 0ustar nileshnilesh% Generated by roxygen2: do not edit by hand % Please edit documentation in R/s2-cell.R \name{s2_cell_is_valid} \alias{s2_cell_is_valid} \alias{s2_cell_debug_string} \alias{s2_cell_to_lnglat} \alias{s2_cell_center} \alias{s2_cell_boundary} \alias{s2_cell_polygon} \alias{s2_cell_vertex} \alias{s2_cell_level} \alias{s2_cell_is_leaf} \alias{s2_cell_is_face} \alias{s2_cell_area} \alias{s2_cell_area_approx} \alias{s2_cell_parent} \alias{s2_cell_child} \alias{s2_cell_edge_neighbour} \alias{s2_cell_contains} \alias{s2_cell_distance} \alias{s2_cell_max_distance} \alias{s2_cell_may_intersect} \alias{s2_cell_common_ancestor_level} \alias{s2_cell_common_ancestor_level_agg} \title{S2 cell operators} \usage{ s2_cell_is_valid(x) s2_cell_debug_string(x) s2_cell_to_lnglat(x) s2_cell_center(x) s2_cell_boundary(x) s2_cell_polygon(x) s2_cell_vertex(x, k) s2_cell_level(x) s2_cell_is_leaf(x) s2_cell_is_face(x) s2_cell_area(x, radius = s2_earth_radius_meters()) s2_cell_area_approx(x, radius = s2_earth_radius_meters()) s2_cell_parent(x, level = -1L) s2_cell_child(x, k) s2_cell_edge_neighbour(x, k) s2_cell_contains(x, y) s2_cell_distance(x, y, radius = s2_earth_radius_meters()) s2_cell_max_distance(x, y, radius = s2_earth_radius_meters()) s2_cell_may_intersect(x, y) s2_cell_common_ancestor_level(x, y) s2_cell_common_ancestor_level_agg(x, na.rm = FALSE) } \arguments{ \item{x, y}{An \code{\link[=s2_cell]{s2_cell()}} vector} \item{k}{An integer between 0 and 3} \item{radius}{The radius to use (e.g., \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}})} \item{level}{An integer between 0 and 30, inclusive.} \item{na.rm}{Remove NAs prior to computing aggregate?} } \description{ S2 cell operators } s2/README.md0000644000175000017510000002045015010321446012205 0ustar nileshnilesh # s2 [![R-CMD-check](https://github.com/r-spatial/s2/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-spatial/s2/actions/workflows/R-CMD-check.yaml) [![codecov](https://codecov.io/gh/r-spatial/s2/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-spatial/s2) [![CRAN](http://www.r-pkg.org/badges/version/s2)](https://cran.r-project.org/package=s2) [![Downloads](http://cranlogs.r-pkg.org/badges/s2?color=brightgreen)](https://www.r-pkg.org/pkg/s2) The s2 R package provides bindings to Google’s [S2Geometry](http://s2geometry.io) library. The package exposes an API similar to Google’s [BigQuery Geography API](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions), whose functions also operate on spherical geometries. Package [sf](https://cran.r-project.org/package=sf) uses this package by default for nearly all its geometrical operations on objects with ellipsoidal (unprojected) coordinates; in cases where it doesn’t, such as `st_relate()`, it emits a warning. This package is a complete rewrite of an earlier CRAN package s2 with versions up to 0.4-2, for which the sources are found [here](https://github.com/spatstat/s2/). ## Installation You can install the released version of s2 from [CRAN](https://CRAN.R-project.org) with: ``` r install.packages("s2") ``` And the development version from [GitHub](https://github.com/) with: ``` r # install.packages("remotes") remotes::install_github("r-spatial/s2") ``` The S2 package requires [Abseil](https://github.com/abseil/abseil-cpp) and OpenSSL. You can install these using a system package manager on most platforms: - Windows: Both OpenSSL and Abseil are available from RTools since R 4.3 - MacOS: `brew install openssl abseil` - Debian/Ubuntu: `apt-get install libssl-dev libabsl-dev` - Fedora: `dnf install openssl-devel abseil-cpp-devel` - Alpine: `apk add abseil-cpp` ## Example The s2 package provides geometry transformers and predicates similar to those found in [GEOS](https://libgeos.org), except instead of assuming a planar geometry, s2’s functions work in latitude and longitude and assume a spherical geometry: ``` r library(s2) s2_contains( # polygon containing much of the northern hemisphere "POLYGON ((-63.5 44.6, -149.75 61.20, 116.4 40.2, 13.5 52.51, -63.5 44.6))", # ...should contain the north pole "POINT (0 90)" ) #> [1] TRUE ``` The [sf package](https://r-spatial.github.io/sf/) uses s2 for geographic coordinates by default (this can be confirmed by calling `sf::sf_use_s2()`). The sf package also supports creating s2 vectors using `as_s2_geography()`: ``` r library(dplyr) library(sf) nc_s2 <- read_sf(system.file("shape/nc.shp", package = "sf")) %>% mutate(geometry = as_s2_geography(geometry)) %>% as_tibble() %>% select(NAME, geometry) nc_s2 #> # A tibble: 100 × 2 #> NAME geometry #> #> 1 Ashe POLYGON ((-81.4528885 36.2395859, -81.4310379 36.2607193, -81.41… #> 2 Alleghany POLYGON ((-81.1766739 36.4154434, -81.1533661 36.4247398, -81.13… #> 3 Surry POLYGON ((-80.4530106 36.2570877, -80.4353104 36.5510445, -80.61… #> 4 Currituck MULTIPOLYGON (((-75.9419327 36.2943382, -75.9575119 36.2594528, … #> 5 Northampton POLYGON ((-77.1419601 36.4170647, -77.1393204 36.4564781, -77.12… #> 6 Hertford POLYGON ((-76.7074966 36.2661324, -76.7413483 36.3151665, -76.92… #> 7 Camden POLYGON ((-76.0173492 36.3377304, -76.0328751 36.3359756, -76.04… #> 8 Gates POLYGON ((-76.46035 36.3738976, -76.5024643 36.4522858, -76.4983… #> 9 Warren POLYGON ((-78.1347198 36.2365837, -78.1096268 36.2135086, -78.05… #> 10 Stokes POLYGON ((-80.0240555 36.5450249, -80.0480957 36.5471344, -80.43… #> # ℹ 90 more rows ``` Use accessors to extract information about geometries: ``` r nc_s2 %>% mutate( area = s2_area(geometry), perimeter = s2_perimeter(geometry) ) #> # A tibble: 100 × 4 #> NAME geometry area perimeter #> #> 1 Ashe POLYGON ((-81.4528885 36.2395859, -81.4310379 3… 1.14e9 141627. #> 2 Alleghany POLYGON ((-81.1766739 36.4154434, -81.1533661 3… 6.11e8 119876. #> 3 Surry POLYGON ((-80.4530106 36.2570877, -80.4353104 3… 1.42e9 160458. #> 4 Currituck MULTIPOLYGON (((-75.9419327 36.2943382, -75.957… 6.94e8 301644. #> 5 Northampton POLYGON ((-77.1419601 36.4170647, -77.1393204 3… 1.52e9 211794. #> 6 Hertford POLYGON ((-76.7074966 36.2661324, -76.7413483 3… 9.68e8 160780. #> 7 Camden POLYGON ((-76.0173492 36.3377304, -76.0328751 3… 6.16e8 150430. #> 8 Gates POLYGON ((-76.46035 36.3738976, -76.5024643 36.… 9.03e8 123170. #> 9 Warren POLYGON ((-78.1347198 36.2365837, -78.1096268 3… 1.18e9 141073. #> 10 Stokes POLYGON ((-80.0240555 36.5450249, -80.0480957 3… 1.23e9 140583. #> # ℹ 90 more rows ``` Use predicates to subset vectors: ``` r nc_s2 %>% filter(s2_contains(geometry, "POINT (-80.9313 35.6196)")) #> # A tibble: 1 × 2 #> NAME geometry #> #> 1 Catawba POLYGON ((-80.9312744 35.6195908, -81.0035782 35.6970558, -81.0547791… ``` Use transformers to create new geometries: ``` r nc_s2 %>% mutate(geometry = s2_boundary(geometry)) #> # A tibble: 100 × 2 #> NAME geometry #> #> 1 Ashe LINESTRING (-81.4528885 36.2395859, -81.4310379 36.2607193, -81.… #> 2 Alleghany LINESTRING (-81.1766739 36.4154434, -81.1533661 36.4247398, -81.… #> 3 Surry LINESTRING (-80.4530106 36.2570877, -80.4353104 36.5510445, -80.… #> 4 Currituck MULTILINESTRING ((-75.9419327 36.2943382, -75.9575119 36.2594528… #> 5 Northampton LINESTRING (-77.1419601 36.4170647, -77.1393204 36.4564781, -77.… #> 6 Hertford LINESTRING (-76.7074966 36.2661324, -76.7413483 36.3151665, -76.… #> 7 Camden LINESTRING (-76.0173492 36.3377304, -76.0328751 36.3359756, -76.… #> 8 Gates LINESTRING (-76.46035 36.3738976, -76.5024643 36.4522858, -76.49… #> 9 Warren LINESTRING (-78.1347198 36.2365837, -78.1096268 36.2135086, -78.… #> 10 Stokes LINESTRING (-80.0240555 36.5450249, -80.0480957 36.5471344, -80.… #> # ℹ 90 more rows ``` Finally, use the WKB or WKT exporters to export to sf or some other package: ``` r nc_s2 %>% mutate(geometry = st_as_sfc(s2_as_binary(geometry))) %>% st_as_sf() #> Simple feature collection with 100 features and 1 field #> Geometry type: GEOMETRY #> Dimension: XY #> Bounding box: xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965 #> CRS: NA #> # A tibble: 100 × 2 #> NAME geometry #> #> 1 Ashe POLYGON ((-81.45289 36.23959, -81.43104 36.26072, -81.41233 36.2… #> 2 Alleghany POLYGON ((-81.17667 36.41544, -81.15337 36.42474, -81.1384 36.41… #> 3 Surry POLYGON ((-80.45301 36.25709, -80.43531 36.55104, -80.61105 36.5… #> 4 Currituck MULTIPOLYGON (((-75.94193 36.29434, -75.95751 36.25945, -75.9137… #> 5 Northampton POLYGON ((-77.14196 36.41706, -77.13932 36.45648, -77.12733 36.4… #> 6 Hertford POLYGON ((-76.7075 36.26613, -76.74135 36.31517, -76.92408 36.39… #> 7 Camden POLYGON ((-76.01735 36.33773, -76.03288 36.33598, -76.04395 36.3… #> 8 Gates POLYGON ((-76.46035 36.3739, -76.50246 36.45229, -76.49834 36.50… #> 9 Warren POLYGON ((-78.13472 36.23658, -78.10963 36.21351, -78.05835 36.2… #> 10 Stokes POLYGON ((-80.02406 36.54502, -80.0481 36.54713, -80.43531 36.55… #> # ℹ 90 more rows ``` ## Acknowledgment This project gratefully acknowledges financial [support](https://r-consortium.org/) from the s2/R/0000755000175000017510000000000014737245171011145 5ustar nileshnileshs2/R/vctrs.R0000644000175000017510000000111214737212474012424 0ustar nileshnilesh vec_proxy.s2_geography <- function(x, ...) { unclass(x) } vec_restore.s2_geography <- function(x, ...) { new_s2_geography(x) } vec_ptype_abbr.s2_geography <- function(x, ...) { "s2_geography" } vec_proxy.s2_cell <- function(x, ...) { unclass(x) } vec_restore.s2_cell <- function(x, ...) { new_s2_cell(x) } vec_ptype_abbr.s2_cell <- function(x, ...) { "s2cell" } vec_proxy.s2_cell_union <- function(x, ...) { unclass(x) } vec_restore.s2_cell_union <- function(x, ...) { new_s2_cell_union(x) } vec_ptype_abbr.s2_cell_union <- function(x, ...) { "s2cellunion" } s2/R/s2-transformers.R0000644000175000017510000002431414737245171014343 0ustar nileshnilesh #' S2 Geography Transformations #' #' These functions operate on one or more geography vectors and #' return a geography vector. #' #' @inheritParams s2_is_collection #' @param na.rm For aggregate calculations use `na.rm = TRUE` #' to drop missing values. #' @param grid_size The grid size to which coordinates should be snapped; #' will be rounded to the nearest power of 10. #' @param options An [s2_options()] object describing the polygon/polyline #' model to use and the snap level. #' @param distance The distance to buffer, in units of `radius`. #' @param max_cells The maximum number of cells to approximate a buffer. #' @param min_level The minimum cell level used to approximate a buffer #' (1 - 30). Setting this value too high will result in unnecessarily #' large geographies, but may help improve buffers along long, narrow #' regions. #' @param tolerance The minimum distance between vertexes to use when #' simplifying a geography. #' #' @inheritSection s2_options Model #' #' @export #' #' @seealso #' BigQuery's geography function reference: #' #' - [ST_BOUNDARY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_boundary) #' - [ST_CENTROID](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_centroid) #' - [ST_CLOSESTPOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_closestpoint) #' - [ST_DIFFERENCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_difference) #' - [ST_INTERSECTION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersection) #' - [ST_UNION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union) #' - [ST_SNAPTOGRID](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_snaptogrid) #' - [ST_SIMPLIFY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_simplify) #' - [ST_UNION_AGG](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union_agg) #' - [ST_CENTROID_AGG](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#s2_centroid_agg) #' #' @examples #' # returns the boundary: #' # empty for point, endpoints of a linestring, #' # perimeter of a polygon #' s2_boundary("POINT (-64 45)") #' s2_boundary("LINESTRING (0 0, 10 0)") #' s2_boundary("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") #' #' # returns the area-weighted centroid, element-wise #' s2_centroid("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") #' s2_centroid("LINESTRING (0 0, 10 0)") #' #' # s2_point_on_surface guarantees a point on surface #' # Note: this is not the same as st_point_on_surface #' s2_centroid("POLYGON ((0 0, 10 0, 1 1, 0 10, 0 0))") #' s2_point_on_surface("POLYGON ((0 0, 10 0, 1 1, 0 10, 0 0))") #' #' # returns the unweighted centroid of the entire input #' s2_centroid_agg(c("POINT (0 0)", "POINT (10 0)")) #' #' # returns the closest point on x to y #' s2_closest_point( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POINT (0 90)" # north pole! #' ) #' #' # returns the shortest possible line between x and y #' s2_minimum_clearance_line_between( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POINT (0 90)" # north pole! #' ) #' #' # binary operations: difference, symmetric difference, intersection and union #' s2_difference( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", #' # 32 bit platforms may need to set snap rounding #' s2_options(snap = s2_snap_level(30)) #' ) #' #' s2_sym_difference( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", #' # 32 bit platforms may need to set snap rounding #' s2_options(snap = s2_snap_level(30)) #' ) #' #' s2_intersection( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", #' # 32 bit platforms may need to set snap rounding #' s2_options(snap = s2_snap_level(30)) #' ) #' #' s2_union( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", #' # 32 bit platforms may need to set snap rounding #' s2_options(snap = s2_snap_level(30)) #' ) #' #' # s2_convex_hull_agg builds the convex hull of a list of geometries #' s2_convex_hull_agg( #' c( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" #' ) #' ) #' #' # use s2_union_agg() to aggregate geographies in a vector #' s2_coverage_union_agg( #' c( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" #' ), #' # 32 bit platforms may need to set snap rounding #' s2_options(snap = s2_snap_level(30)) #' ) #' #' # snap to grid rounds coordinates to a specified grid size #' s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2) #' #' s2_boundary <- function(x) { new_s2_geography(cpp_s2_boundary(as_s2_geography(x))) } #' @rdname s2_boundary #' @export s2_centroid <- function(x) { new_s2_geography(cpp_s2_centroid(as_s2_geography(x))) } #' @rdname s2_boundary #' @export s2_closest_point <- function(x, y) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) new_s2_geography(cpp_s2_closest_point(recycled[[1]], recycled[[2]])) } #' @rdname s2_boundary #' @export s2_minimum_clearance_line_between <- function(x, y) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) new_s2_geography(cpp_s2_minimum_clearance_line_between(recycled[[1]], recycled[[2]])) } #' @rdname s2_boundary #' @export s2_difference <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) new_s2_geography(cpp_s2_difference(recycled[[1]], recycled[[2]], options)) } #' @rdname s2_boundary #' @export s2_sym_difference <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) new_s2_geography(cpp_s2_sym_difference(recycled[[1]], recycled[[2]], options)) } #' @rdname s2_boundary #' @export s2_intersection <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) new_s2_geography(cpp_s2_intersection(recycled[[1]], recycled[[2]], options)) } #' @rdname s2_boundary #' @export s2_union <- function(x, y = NULL, options = s2_options()) { x <- as_s2_geography(x) if (is.null(y)) { new_s2_geography(cpp_s2_unary_union(x, options)) } else { recycled <- recycle_common(x, as_s2_geography(y)) new_s2_geography(cpp_s2_union(recycled[[1]], recycled[[2]], options)) } } #' @rdname s2_boundary #' @export s2_snap_to_grid <- function(x, grid_size) { s2_rebuild( x, options = s2_options( snap = s2_snap_precision(10^(-log10(grid_size))), duplicate_edges = TRUE ) ) } #' @rdname s2_boundary #' @export s2_simplify <- function(x, tolerance, radius = s2_earth_radius_meters()) { s2_rebuild(x, options = s2_options(snap_radius = tolerance / radius, simplify_edge_chains = TRUE)) } #' @rdname s2_boundary #' @export s2_rebuild <- function(x, options = s2_options()) { new_s2_geography(cpp_s2_rebuild(as_s2_geography(x), options)) } #' @rdname s2_boundary #' @export s2_buffer_cells <- function(x, distance, max_cells = 1000, min_level = -1, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), distance / radius, max_cells, min_level) new_s2_geography(cpp_s2_buffer_cells(recycled[[1]], recycled[[2]], recycled[[3]], recycled[[4]])) } #' @rdname s2_boundary #' @export s2_convex_hull <- function(x) { new_s2_geography(cpp_s2_convex_hull(as_s2_geography(x))) } #' @rdname s2_boundary #' @export s2_centroid_agg <- function(x, na.rm = FALSE) { new_s2_geography(cpp_s2_centroid_agg(as_s2_geography(x), naRm = na.rm)) } #' @rdname s2_boundary #' @export s2_coverage_union_agg <- function(x, options = s2_options(), na.rm = FALSE) { new_s2_geography(cpp_s2_coverage_union_agg(as_s2_geography(x), options, na.rm)) } #' @rdname s2_boundary #' @export s2_rebuild_agg <- function(x, options = s2_options(), na.rm = FALSE) { new_s2_geography(cpp_s2_rebuild_agg(as_s2_geography(x), options, na.rm)) } #' @rdname s2_boundary #' @export s2_union_agg <- function(x, options = s2_options(), na.rm = FALSE) { new_s2_geography(cpp_s2_union_agg(s2_union(x, options = options), options, na.rm)) } #' @rdname s2_boundary #' @export s2_convex_hull_agg <- function(x, na.rm = FALSE) { new_s2_geography(cpp_s2_convex_hull_agg(as_s2_geography(x), na.rm)) } #' Linear referencing #' #' @param x A simple polyline geography vector #' @param y A simple point geography vector. The point will be #' snapped to the nearest point on `x` for the purposes of #' interpolation. #' @param distance A distance along `x` in `radius` units. #' @param distance_normalized A `distance` normalized to [s2_length()] of #' `x`. #' @inheritParams s2_is_collection #' #' @return #' - `s2_interpolate()` returns the point on `x`, `distance` meters #' along the line. #' - `s2_interpolate_normalized()` returns the point on `x` interpolated #' to a fraction along the line. #' - `s2_project()` returns the `distance` that `point` occurs along `x`. #' - `s2_project_normalized()` returns the `distance_normalized` along `x` #' where `point` occurs. #' @export #' #' @examples #' s2_project_normalized("LINESTRING (0 0, 0 90)", "POINT (0 22.5)") #' s2_project("LINESTRING (0 0, 0 90)", "POINT (0 22.5)") #' s2_interpolate_normalized("LINESTRING (0 0, 0 90)", 0.25) #' s2_interpolate("LINESTRING (0 0, 0 90)", 2501890) #' s2_interpolate <- function(x, distance, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), distance / radius) length <- cpp_s2_length(recycled[[1]]) new_s2_geography( cpp_s2_interpolate_normalized(recycled[[1]], distance / radius / length) ) } #' @rdname s2_interpolate #' @export s2_interpolate_normalized <- function(x, distance_normalized) { recycled <- recycle_common(as_s2_geography(x), distance_normalized) new_s2_geography( cpp_s2_interpolate_normalized(recycled[[1]], distance_normalized) ) } #' @rdname s2_boundary #' @export s2_point_on_surface <- function(x, na.rm = FALSE) { new_s2_geography(cpp_s2_point_on_surface(as_s2_geography(x))) } s2/R/RcppExports.R0000644000175000017510000003152414737231173013563 0ustar nileshnilesh# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 cpp_s2_init <- function() { invisible(.Call(`_s2_cpp_s2_init`)) } cpp_s2_is_collection <- function(geog) { .Call(`_s2_cpp_s2_is_collection`, geog) } cpp_s2_is_valid <- function(geog) { .Call(`_s2_cpp_s2_is_valid`, geog) } cpp_s2_is_valid_reason <- function(geog) { .Call(`_s2_cpp_s2_is_valid_reason`, geog) } cpp_s2_dimension <- function(geog) { .Call(`_s2_cpp_s2_dimension`, geog) } cpp_s2_num_points <- function(geog) { .Call(`_s2_cpp_s2_num_points`, geog) } cpp_s2_is_empty <- function(geog) { .Call(`_s2_cpp_s2_is_empty`, geog) } cpp_s2_area <- function(geog) { .Call(`_s2_cpp_s2_area`, geog) } cpp_s2_length <- function(geog) { .Call(`_s2_cpp_s2_length`, geog) } cpp_s2_perimeter <- function(geog) { .Call(`_s2_cpp_s2_perimeter`, geog) } cpp_s2_x <- function(geog) { .Call(`_s2_cpp_s2_x`, geog) } cpp_s2_y <- function(geog) { .Call(`_s2_cpp_s2_y`, geog) } cpp_s2_project_normalized <- function(geog1, geog2) { .Call(`_s2_cpp_s2_project_normalized`, geog1, geog2) } cpp_s2_distance <- function(geog1, geog2) { .Call(`_s2_cpp_s2_distance`, geog1, geog2) } cpp_s2_max_distance <- function(geog1, geog2) { .Call(`_s2_cpp_s2_max_distance`, geog1, geog2) } cpp_s2_bounds_cap <- function(geog) { .Call(`_s2_cpp_s2_bounds_cap`, geog) } cpp_s2_bounds_rect <- function(geog) { .Call(`_s2_cpp_s2_bounds_rect`, geog) } cpp_s2_cell_union_normalize <- function(cellUnionVector) { .Call(`_s2_cpp_s2_cell_union_normalize`, cellUnionVector) } cpp_s2_cell_union_is_na <- function(cellUnionVector) { .Call(`_s2_cpp_s2_cell_union_is_na`, cellUnionVector) } cpp_s2_cell_union_contains <- function(cellUnionVector1, cellUnionVector2) { .Call(`_s2_cpp_s2_cell_union_contains`, cellUnionVector1, cellUnionVector2) } cpp_s2_cell_union_contains_cell <- function(cellUnionVector, cellIdVector) { .Call(`_s2_cpp_s2_cell_union_contains_cell`, cellUnionVector, cellIdVector) } cpp_s2_cell_union_intersects <- function(cellUnionVector1, cellUnionVector2) { .Call(`_s2_cpp_s2_cell_union_intersects`, cellUnionVector1, cellUnionVector2) } cpp_s2_cell_union_intersection <- function(cellUnionVector1, cellUnionVector2) { .Call(`_s2_cpp_s2_cell_union_intersection`, cellUnionVector1, cellUnionVector2) } cpp_s2_cell_union_union <- function(cellUnionVector1, cellUnionVector2) { .Call(`_s2_cpp_s2_cell_union_union`, cellUnionVector1, cellUnionVector2) } cpp_s2_cell_union_difference <- function(cellUnionVector1, cellUnionVector2) { .Call(`_s2_cpp_s2_cell_union_difference`, cellUnionVector1, cellUnionVector2) } cpp_s2_geography_from_cell_union <- function(cellUnionVector) { .Call(`_s2_cpp_s2_geography_from_cell_union`, cellUnionVector) } cpp_s2_covering_cell_ids <- function(geog, min_level, max_level, max_cells, buffer, interior) { .Call(`_s2_cpp_s2_covering_cell_ids`, geog, min_level, max_level, max_cells, buffer, interior) } cpp_s2_covering_cell_ids_agg <- function(geog, min_level, max_level, max_cells, buffer, interior, naRm) { .Call(`_s2_cpp_s2_covering_cell_ids_agg`, geog, min_level, max_level, max_cells, buffer, interior, naRm) } cpp_s2_cell_sentinel <- function() { .Call(`_s2_cpp_s2_cell_sentinel`) } cpp_s2_cell_from_string <- function(cellString) { .Call(`_s2_cpp_s2_cell_from_string`, cellString) } cpp_s2_cell_from_lnglat <- function(lnglat) { .Call(`_s2_cpp_s2_cell_from_lnglat`, lnglat) } cpp_s2_cell_to_lnglat <- function(cellId) { .Call(`_s2_cpp_s2_cell_to_lnglat`, cellId) } cpp_s2_cell_to_cell_union <- function(cellId) { .Call(`_s2_cpp_s2_cell_to_cell_union`, cellId) } cpp_s2_cell_is_na <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_is_na`, cellIdVector) } cpp_s2_cell_sort <- function(cellIdVector, decreasing) { .Call(`_s2_cpp_s2_cell_sort`, cellIdVector, decreasing) } cpp_s2_cell_range <- function(cellIdVector, naRm) { .Call(`_s2_cpp_s2_cell_range`, cellIdVector, naRm) } cpp_s2_cell_unique <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_unique`, cellIdVector) } cpp_s2_cell_to_string <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_to_string`, cellIdVector) } cpp_s2_cell_debug_string <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_debug_string`, cellIdVector) } cpp_s2_cell_is_valid <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_is_valid`, cellIdVector) } cpp_s2_cell_center <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_center`, cellIdVector) } cpp_s2_cell_polygon <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_polygon`, cellIdVector) } cpp_s2_cell_vertex <- function(cellIdVector, k) { .Call(`_s2_cpp_s2_cell_vertex`, cellIdVector, k) } cpp_s2_cell_level <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_level`, cellIdVector) } cpp_s2_cell_area <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_area`, cellIdVector) } cpp_s2_cell_area_approx <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_area_approx`, cellIdVector) } cpp_s2_cell_parent <- function(cellIdVector, level) { .Call(`_s2_cpp_s2_cell_parent`, cellIdVector, level) } cpp_s2_cell_child <- function(cellIdVector, k) { .Call(`_s2_cpp_s2_cell_child`, cellIdVector, k) } cpp_s2_cell_edge_neighbour <- function(cellIdVector, k) { .Call(`_s2_cpp_s2_cell_edge_neighbour`, cellIdVector, k) } cpp_s2_cell_cummax <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_cummax`, cellIdVector) } cpp_s2_cell_cummin <- function(cellIdVector) { .Call(`_s2_cpp_s2_cell_cummin`, cellIdVector) } cpp_s2_cell_eq <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_eq`, cellIdVector1, cellIdVector2) } cpp_s2_cell_neq <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_neq`, cellIdVector1, cellIdVector2) } cpp_s2_cell_lt <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_lt`, cellIdVector1, cellIdVector2) } cpp_s2_cell_lte <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_lte`, cellIdVector1, cellIdVector2) } cpp_s2_cell_gte <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_gte`, cellIdVector1, cellIdVector2) } cpp_s2_cell_gt <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_gt`, cellIdVector1, cellIdVector2) } cpp_s2_cell_contains <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_contains`, cellIdVector1, cellIdVector2) } cpp_s2_cell_may_intersect <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_may_intersect`, cellIdVector1, cellIdVector2) } cpp_s2_cell_distance <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_distance`, cellIdVector1, cellIdVector2) } cpp_s2_cell_max_distance <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_max_distance`, cellIdVector1, cellIdVector2) } cpp_s2_cell_common_ancestor_level <- function(cellIdVector1, cellIdVector2) { .Call(`_s2_cpp_s2_cell_common_ancestor_level`, cellIdVector1, cellIdVector2) } cpp_s2_cell_common_ancestor_level_agg <- function(cellId) { .Call(`_s2_cpp_s2_cell_common_ancestor_level_agg`, cellId) } s2_geography_full <- function(x) { .Call(`_s2_s2_geography_full`, x) } cpp_s2_geography_is_na <- function(geog) { .Call(`_s2_cpp_s2_geography_is_na`, geog) } s2_lnglat_from_s2_point <- function(s2_point) { .Call(`_s2_s2_lnglat_from_s2_point`, s2_point) } s2_point_from_s2_lnglat <- function(s2_lnglat) { .Call(`_s2_s2_point_from_s2_lnglat`, s2_lnglat) } cpp_s2_closest_feature <- function(geog1, geog2) { .Call(`_s2_cpp_s2_closest_feature`, geog1, geog2) } cpp_s2_farthest_feature <- function(geog1, geog2) { .Call(`_s2_cpp_s2_farthest_feature`, geog1, geog2) } cpp_s2_closest_edges <- function(geog1, geog2, n, min_distance, max_distance) { .Call(`_s2_cpp_s2_closest_edges`, geog1, geog2, n, min_distance, max_distance) } cpp_s2_may_intersect_matrix <- function(geog1, geog2, maxEdgesPerCell, maxFeatureCells, s2options) { .Call(`_s2_cpp_s2_may_intersect_matrix`, geog1, geog2, maxEdgesPerCell, maxFeatureCells, s2options) } cpp_s2_contains_matrix <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_contains_matrix`, geog1, geog2, s2options) } cpp_s2_within_matrix <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_within_matrix`, geog1, geog2, s2options) } cpp_s2_intersects_matrix <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_intersects_matrix`, geog1, geog2, s2options) } cpp_s2_equals_matrix <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_equals_matrix`, geog1, geog2, s2options) } cpp_s2_touches_matrix <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_touches_matrix`, geog1, geog2, s2options) } cpp_s2_dwithin_matrix <- function(geog1, geog2, distance) { .Call(`_s2_cpp_s2_dwithin_matrix`, geog1, geog2, distance) } cpp_s2_distance_matrix <- function(geog1, geog2) { .Call(`_s2_cpp_s2_distance_matrix`, geog1, geog2) } cpp_s2_max_distance_matrix <- function(geog1, geog2) { .Call(`_s2_cpp_s2_max_distance_matrix`, geog1, geog2) } cpp_s2_contains_matrix_brute_force <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_contains_matrix_brute_force`, geog1, geog2, s2options) } cpp_s2_within_matrix_brute_force <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_within_matrix_brute_force`, geog1, geog2, s2options) } cpp_s2_intersects_matrix_brute_force <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_intersects_matrix_brute_force`, geog1, geog2, s2options) } cpp_s2_disjoint_matrix_brute_force <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_disjoint_matrix_brute_force`, geog1, geog2, s2options) } cpp_s2_equals_matrix_brute_force <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_equals_matrix_brute_force`, geog1, geog2, s2options) } cpp_s2_dwithin_matrix_brute_force <- function(geog1, geog2, distance) { .Call(`_s2_cpp_s2_dwithin_matrix_brute_force`, geog1, geog2, distance) } cpp_s2_intersects <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_intersects`, geog1, geog2, s2options) } cpp_s2_equals <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_equals`, geog1, geog2, s2options) } cpp_s2_contains <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_contains`, geog1, geog2, s2options) } cpp_s2_touches <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_touches`, geog1, geog2, s2options) } cpp_s2_dwithin <- function(geog1, geog2, distance) { .Call(`_s2_cpp_s2_dwithin`, geog1, geog2, distance) } cpp_s2_prepared_dwithin <- function(geog1, geog2, distance) { .Call(`_s2_cpp_s2_prepared_dwithin`, geog1, geog2, distance) } cpp_s2_intersects_box <- function(geog, lng1, lat1, lng2, lat2, detail, s2options) { .Call(`_s2_cpp_s2_intersects_box`, geog, lng1, lat1, lng2, lat2, detail, s2options) } cpp_s2_intersection <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_intersection`, geog1, geog2, s2options) } cpp_s2_union <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_union`, geog1, geog2, s2options) } cpp_s2_difference <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_difference`, geog1, geog2, s2options) } cpp_s2_sym_difference <- function(geog1, geog2, s2options) { .Call(`_s2_cpp_s2_sym_difference`, geog1, geog2, s2options) } cpp_s2_coverage_union_agg <- function(geog, s2options, naRm) { .Call(`_s2_cpp_s2_coverage_union_agg`, geog, s2options, naRm) } cpp_s2_union_agg <- function(geog, s2options, naRm) { .Call(`_s2_cpp_s2_union_agg`, geog, s2options, naRm) } cpp_s2_centroid_agg <- function(geog, naRm) { .Call(`_s2_cpp_s2_centroid_agg`, geog, naRm) } cpp_s2_rebuild_agg <- function(geog, s2options, naRm) { .Call(`_s2_cpp_s2_rebuild_agg`, geog, s2options, naRm) } cpp_s2_closest_point <- function(geog1, geog2) { .Call(`_s2_cpp_s2_closest_point`, geog1, geog2) } cpp_s2_minimum_clearance_line_between <- function(geog1, geog2) { .Call(`_s2_cpp_s2_minimum_clearance_line_between`, geog1, geog2) } cpp_s2_centroid <- function(geog) { .Call(`_s2_cpp_s2_centroid`, geog) } cpp_s2_point_on_surface <- function(geog) { .Call(`_s2_cpp_s2_point_on_surface`, geog) } cpp_s2_boundary <- function(geog) { .Call(`_s2_cpp_s2_boundary`, geog) } cpp_s2_rebuild <- function(geog, s2options) { .Call(`_s2_cpp_s2_rebuild`, geog, s2options) } cpp_s2_unary_union <- function(geog, s2options) { .Call(`_s2_cpp_s2_unary_union`, geog, s2options) } cpp_s2_interpolate_normalized <- function(geog, distanceNormalized) { .Call(`_s2_cpp_s2_interpolate_normalized`, geog, distanceNormalized) } cpp_s2_buffer_cells <- function(geog, distance, maxCells, minLevel) { .Call(`_s2_cpp_s2_buffer_cells`, geog, distance, maxCells, minLevel) } cpp_s2_convex_hull <- function(geog) { .Call(`_s2_cpp_s2_convex_hull`, geog) } cpp_s2_convex_hull_agg <- function(geog, naRm) { .Call(`_s2_cpp_s2_convex_hull_agg`, geog, naRm) } s2/R/data.R0000644000175000017510000000367414737212474012213 0ustar nileshnilesh #' Low-resolution world boundaries, timezones, and cities #' #' Well-known binary versions of the [Natural Earth](https://www.naturalearthdata.com/) #' low-resolution world boundaries and timezone boundaries. #' #' @param name The name of a country, continent, city, or `NULL` #' for all features. #' @param utc_offset_min,utc_offset_max Minimum and/or maximum timezone #' offsets. #' #' @format A data.frame with columns `name` (character), and #' `geometry` (wk_wkb) #' @source [Natural Earth Data](https://www.naturalearthdata.com/) #' @examples #' head(s2_data_countries()) #' s2_data_countries("Germany") #' s2_data_countries("Europe") #' #' head(s2_data_timezones()) #' s2_data_timezones(-4) #' #' head(s2_data_cities()) #' s2_data_cities("Cairo") #' "s2_data_tbl_countries" #' @rdname s2_data_tbl_countries "s2_data_tbl_timezones" #' @rdname s2_data_tbl_countries "s2_data_tbl_cities" #' @rdname s2_data_tbl_countries #' @export s2_data_countries <- function(name = NULL) { df <- s2::s2_data_tbl_countries if (is.null(name)) { wkb <- df$geometry } else { wkb <- df$geometry[(df$name %in% name) | (df$continent %in% name)] } as_s2_geography(wkb) } #' @rdname s2_data_tbl_countries #' @export s2_data_timezones <- function(utc_offset_min = NULL, utc_offset_max = utc_offset_min) { df <- s2::s2_data_tbl_timezones if (is.null(utc_offset_min)) { wkb <- df$geometry } else { matches <- (df$utc_offset >= utc_offset_min) & (df$utc_offset <= utc_offset_max) wkb <- df$geometry[matches] } as_s2_geography(wkb) } #' @rdname s2_data_tbl_countries #' @export s2_data_cities <- function(name = NULL) { df <- s2::s2_data_tbl_cities if (is.null(name)) { wkb <- df$geometry } else { wkb <- df$geometry[df$name %in% name] } as_s2_geography(wkb) } #' Example Geometries #' #' These geometries are toy examples useful for testing various coordinate #' shuffling operations in the s2 package. #' "s2_data_example_wkt" s2/R/s2-matrix.R0000644000175000017510000001650114737212474013121 0ustar nileshnilesh #' Matrix Functions #' #' These functions are similar to accessors and predicates, but instead of #' recycling `x` and `y` to a common length and returning a vector of that #' length, these functions return a vector of length `x` with each element #' `i` containing information about how the entire vector `y` relates to #' the feature at `x[i]`. #' #' @inheritParams s2_is_collection #' @inheritParams s2_contains #' @param x,y Geography vectors, coerced using [as_s2_geography()]. #' `x` is considered the source, where as `y` is considered the target. #' @param k The number of closest edges to consider when searching. Note #' that in S2 a point is also considered an edge. #' @param min_distance The minimum distance to consider when searching for #' edges. This filter is applied after the search is complete (i.e., #' may cause fewer than `k` values to be returned). #' @param max_distance The maximum distance to consider when searching for #' edges. This filter is applied before the search. #' @param max_edges_per_cell For [s2_may_intersect_matrix()], #' this values controls the nature of the index on `y`, with higher values #' leading to coarser index. Values should be between 10 and 50; the default #' of 50 is adequate for most use cases, but for specialized operations users #' may wish to use a lower value to increase performance. #' @param max_feature_cells For [s2_may_intersect_matrix()], this value #' controls the approximation of `x` used to identify potential intersections #' on `y`. The default value of 4 gives the best performance for most operations, #' but for specialized operations users may wish to use a higher value to increase #' performance. #' #' @return A vector of length `x`. #' @export #' #' @seealso #' See pairwise predicate functions (e.g., [s2_intersects()]). #' #' @examples #' city_names <- c("Vatican City", "San Marino", "Luxembourg") #' cities <- s2_data_cities(city_names) #' country_names <- s2_data_tbl_countries$name #' countries <- s2_data_countries() #' #' # closest feature returns y indices of the closest feature #' # for each feature in x #' country_names[s2_closest_feature(cities, countries)] #' #' # farthest feature returns y indices of the farthest feature #' # for each feature in x #' country_names[s2_farthest_feature(cities, countries)] #' #' # use s2_closest_edges() to find the k-nearest neighbours #' nearest <- s2_closest_edges(cities, cities, k = 2, min_distance = 0) #' city_names #' city_names[unlist(nearest)] #' #' # predicate matrices #' country_names[s2_intersects_matrix(cities, countries)[[1]]] #' #' # distance matrices #' s2_distance_matrix(cities, cities) #' s2_max_distance_matrix(cities, countries[1:4]) #' s2_closest_feature <- function(x, y) { cpp_s2_closest_feature(as_s2_geography(x), as_s2_geography(y)) } #' @rdname s2_closest_feature #' @export s2_closest_edges <- function(x, y, k, min_distance = -1, max_distance = Inf, radius = s2_earth_radius_meters()) { stopifnot(k >= 1) cpp_s2_closest_edges( as_s2_geography(x), as_s2_geography(y), k, min_distance / radius, max_distance / radius ) } #' @rdname s2_closest_feature #' @export s2_farthest_feature <- function(x, y) { cpp_s2_farthest_feature(as_s2_geography(x), as_s2_geography(y)) } #' @rdname s2_closest_feature #' @export s2_distance_matrix <- function(x, y, radius = s2_earth_radius_meters()) { cpp_s2_distance_matrix(as_s2_geography(x), as_s2_geography(y)) * radius } #' @rdname s2_closest_feature #' @export s2_max_distance_matrix <- function(x, y, radius = s2_earth_radius_meters()) { cpp_s2_max_distance_matrix(as_s2_geography(x), as_s2_geography(y)) * radius } #' @rdname s2_closest_feature #' @export s2_contains_matrix <- function(x, y, options = s2_options(model = "open")) { cpp_s2_contains_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_within_matrix <- function(x, y, options = s2_options(model = "open")) { cpp_s2_within_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_covers_matrix <- function(x, y, options = s2_options(model = "closed")) { cpp_s2_contains_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_covered_by_matrix <- function(x, y, options = s2_options(model = "closed")) { cpp_s2_within_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_intersects_matrix <- function(x, y, options = s2_options()) { cpp_s2_intersects_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_disjoint_matrix <- function(x, y, options = s2_options()) { # disjoint is the odd one out, in that it requires a negation of intersects # this is inconvenient to do on the C++ level, and is easier to maintain # with setdiff() here (unless somebody complains that this is slow) intersection <- cpp_s2_intersects_matrix(as_s2_geography(x), as_s2_geography(y), options) Map(setdiff, list(seq_along(y)), intersection) } #' @rdname s2_closest_feature #' @export s2_equals_matrix <- function(x, y, options = s2_options()) { cpp_s2_equals_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_touches_matrix <- function(x, y, options = s2_options()) { cpp_s2_touches_matrix(as_s2_geography(x), as_s2_geography(y), options) } #' @rdname s2_closest_feature #' @export s2_dwithin_matrix <- function(x, y, distance, radius = s2_earth_radius_meters()) { cpp_s2_dwithin_matrix(as_s2_geography(x), as_s2_geography(y), distance / radius) } #' @rdname s2_closest_feature #' @export s2_may_intersect_matrix <- function(x, y, max_edges_per_cell = 50, max_feature_cells = 4) { cpp_s2_may_intersect_matrix( as_s2_geography(x), as_s2_geography(y), max_edges_per_cell, max_feature_cells, s2_options() ) } # ------- for testing, non-indexed versions of matrix operators ------- s2_contains_matrix_brute_force <- function(x, y, options = s2_options()) { cpp_s2_contains_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_within_matrix_brute_force <- function(x, y, options = s2_options()) { cpp_s2_within_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_covers_matrix_brute_force <- function(x, y, options = s2_options(model = "closed")) { cpp_s2_contains_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_covered_by_matrix_brute_force <- function(x, y, options = s2_options(model = "closed")) { cpp_s2_within_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_intersects_matrix_brute_force <- function(x, y, options = s2_options()) { cpp_s2_intersects_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_disjoint_matrix_brute_force <- function(x, y, options = s2_options()) { cpp_s2_disjoint_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_equals_matrix_brute_force <- function(x, y, options = s2_options()) { cpp_s2_equals_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options) } s2_dwithin_matrix_brute_force <- function(x, y, distance, radius = s2_earth_radius_meters()) { cpp_s2_dwithin_matrix_brute_force( as_s2_geography(x), as_s2_geography(y), distance / radius ) } s2/R/wk-utils.R0000644000175000017510000000760514737212474013057 0ustar nileshnilesh #' Low-level wk filters and handlers #' #' @inheritParams wk::wk_handle #' @param projection,s2_projection One of [s2_projection_plate_carree()] or #' [s2_projection_mercator()] #' @param tessellate_tol,s2_tessellate_tol An angle in radians. #' Points will not be added if a line segment is within this #' distance of a point. #' @param x_scale The maximum x value of the projection #' @param centre The center point of the orthographic projection #' @param epsilon_east_west,epsilon_north_south Use a positive number to #' define the edges of a Cartesian world slightly inward from -180, -90, #' 180, 90. This may be used to define a world outline for a projection where #' projecting at the extreme edges of the earth results in a non-finite value. #' @inheritParams as_s2_geography #' #' @return #' - `s2_projection_plate_carree()`, `s2_projection_mercator()`: An external pointer #' to an S2 projection. #' @importFrom wk wk_handle #' @export #' wk_handle.s2_geography <- function(handleable, handler, ..., s2_projection = s2_projection_plate_carree(), s2_tessellate_tol = Inf) { stopifnot(is.null(s2_projection) || inherits(s2_projection, "s2_projection")) attr(handleable, "s2_projection") <- s2_projection if (identical(s2_tessellate_tol, Inf)) { .Call(c_s2_handle_geography, handleable, wk::as_wk_handler(handler)) } else { attr(handleable, "s2_tessellate_tol") <- as.double(s2_tessellate_tol)[1] .Call(c_s2_handle_geography_tessellated, handleable, wk::as_wk_handler(handler)) } } #' @rdname wk_handle.s2_geography #' @export s2_geography_writer <- function(oriented = FALSE, check = TRUE, projection = s2_projection_plate_carree(), tessellate_tol = Inf) { stopifnot(is.null(projection) || inherits(projection, "s2_projection")) wk::new_wk_handler( .Call( c_s2_geography_writer_new, as.logical(oriented)[1], as.logical(check)[1], projection, as.double(tessellate_tol[1]) ), "s2_geography_writer" ) } #' @rdname wk_handle.s2_geography #' @importFrom wk wk_writer #' @method wk_writer s2_geography #' @export wk_writer.s2_geography <- function(handleable, ...) { s2_geography_writer() } #' @rdname wk_handle.s2_geography #' @export s2_trans_point <- function() { wk::new_wk_trans(.Call(c_s2_trans_s2_point_new)) } #' @rdname wk_handle.s2_geography #' @export s2_trans_lnglat <- function() { wk::new_wk_trans(.Call(c_s2_trans_s2_lnglat_new)) } #' @rdname wk_handle.s2_geography #' @export s2_projection_plate_carree <- function(x_scale = 180) { structure( .Call(c_s2_projection_plate_carree, as.double(x_scale)[1]), class = "s2_projection" ) } #' @rdname wk_handle.s2_geography #' @export s2_projection_mercator <- function(x_scale = 20037508.3427892) { structure( .Call(c_s2_projection_mercator, as.double(x_scale)[1]), class = "s2_projection" ) } #' @rdname wk_handle.s2_geography #' @export s2_hemisphere <- function(centre) { cap_to_polygon(centre, pi / 2) } #' @rdname wk_handle.s2_geography #' @export s2_world_plate_carree <- function(epsilon_east_west = 0, epsilon_north_south = 0) { s2_make_polygon( c( -180 + epsilon_east_west, 0, 180 - epsilon_east_west, 180 - epsilon_east_west, 180 - epsilon_east_west, 0, -180 + epsilon_east_west, -180 + epsilon_east_west ), c( -90 + epsilon_north_south, -90 + epsilon_north_south, -90 + epsilon_north_south, 0, 90 - epsilon_north_south, 90 - epsilon_north_south, 90 - epsilon_north_south, 0 ), oriented = TRUE ) } #' @rdname wk_handle.s2_geography #' @export s2_projection_orthographic <- function(centre = s2_lnglat(0, 0)) { centre <- as_s2_lnglat(centre) centre <- as.matrix(centre) structure( .Call(c_s2_projection_orthographic, centre[1:2]), class = "s2_projection" ) } s2/R/s2-options.R0000644000175000017510000001402214737212474013304 0ustar nileshnilesh #' Geography Operation Options #' #' These functions specify defaults for options used to perform operations #' and construct geometries. These are used in predicates (e.g., [s2_intersects()]), #' and boolean operations (e.g., [s2_intersection()]) to specify the model for #' containment and how new geometries should be constructed. #' #' @param model One of 'open', 'semi-open' (default for polygons), #' or 'closed' (default for polylines). See section 'Model' #' @param snap Use `s2_snap_identity()`, `s2_snap_distance()`, `s2_snap_level()`, #' or `s2_snap_precision()` to specify how or if coordinate rounding should #' occur. #' @param snap_radius As opposed to the snap function, which specifies #' the maximum distance a vertex should move, the snap radius (in radians) sets #' the minimum distance between vertices of the output that don't cause vertices #' to move more than the distance specified by the snap function. This can be used #' to simplify the result of a boolean operation. Use -1 to specify that any #' minimum distance is acceptable. #' @param duplicate_edges Use `TRUE` to keep duplicate edges (e.g., duplicate #' points). #' @param edge_type One of 'directed' (default) or 'undirected'. #' @param polyline_type One of 'path' (default) or 'walk'. If 'walk', #' polylines that backtrack are preserved. #' @param polyline_sibling_pairs One of 'discard' (default) or 'keep'. #' @param simplify_edge_chains Use `TRUE` to remove vertices that are within #' `snap_radius` of the original vertex. #' @param split_crossing_edges Use `TRUE` to split crossing polyline edges #' when creating geometries. #' @param idempotent Use `FALSE` to apply snap even if snapping is not necessary #' to satisfy vertex constraints. #' @param validate Use `TRUE` to validate the result from the builder. #' @param level A value from 0 to 30 corresponding to the cell level #' at which snapping should occur. #' @param distance A distance (in radians) denoting the maximum #' distance a vertex should move in the snapping process. #' @param precision A number by which coordinates should be multiplied #' before being rounded. Rounded to the nearest exponent of 10. #' @param dimensions A combination of 'point', 'polyline', and/or 'polygon' #' that can used to constrain the output of [s2_rebuild()] or a #' boolean operation. #' #' @section Model: #' The geometry model indicates whether or not a geometry includes its boundaries. #' Boundaries of line geometries are its end points. #' OPEN geometries do not contain their boundary (`model = "open"`); CLOSED #' geometries (`model = "closed"`) contain their boundary; SEMI-OPEN geometries #' (`model = "semi-open"`) contain half of their boundaries, such that when two polygons #' do not overlap or two lines do not cross, no point exist that belong to #' more than one of the geometries. (This latter form, half-closed, is #' not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on #' which that is based). The default values for [s2_contains()] (open) #' and covers/covered_by (closed) correspond to the SFA standard specification #' of these operators. #' #' @export #' #' @examples #' # use s2_options() to specify containment models, snap level #' # layer creation options, and builder options #' s2_options(model = "closed", snap = s2_snap_level(30)) #' s2_options <- function(model = NULL, snap = s2_snap_identity(), snap_radius = -1, duplicate_edges = FALSE, edge_type = "directed", validate = FALSE, polyline_type = "path", polyline_sibling_pairs = "keep", simplify_edge_chains = FALSE, split_crossing_edges = FALSE, idempotent = FALSE, dimensions = c("point", "polyline", "polygon")) { # check snap radius (passing in a huge snap radius can cause problems) if (snap_radius > 3) { stop( "Snap radius is too large. Did you pass in a snap radius in meters instead of radians?", call. = FALSE ) } structure( list( # model needs to be "unset" by default because there are differences in polygon # and polyline handling by default that are good defaults to preserve model = if (is.null(model)) -1 else match_option(model[1], c("open", "semi-open", "closed"), "model"), snap = snap, snap_radius = snap_radius, duplicate_edges = duplicate_edges, edge_type = match_option(edge_type[1], c("directed", "undirected"), "edge_type"), validate = validate, polyline_type = match_option(polyline_type[1], c("path", "walk"), "polyline_type"), polyline_sibling_pairs = match_option( polyline_sibling_pairs, c("discard", "keep"), "polyline_sibling_pairs" ), simplify_edge_chains = simplify_edge_chains, split_crossing_edges = split_crossing_edges, idempotent = idempotent, dimensions = match_option(dimensions, c("point", "polyline", "polygon"), "dimensions") ), class = "s2_options" ) } #' @rdname s2_options #' @export s2_snap_identity <- function() { structure(list(), class = "snap_identity") } #' @rdname s2_options #' @export s2_snap_level <- function(level) { if (level > 30) { stop("`level` must be an intger between 1 and 30", call. = FALSE) } structure(list(level = level), class = "snap_level") } #' @rdname s2_options #' @export s2_snap_precision <- function(precision) { stopifnot(precision <= 1e17) # https://github.com/r-spatial/s2/issues/248 structure(list(exponent = round(log10(precision))), class = "snap_precision") } #' @rdname s2_options #' @export s2_snap_distance <- function(distance) { structure(list(distance = distance), class = "snap_distance") } match_option <- function(x, options, arg) { result <- match(x, options) if (any(is.na(result))) { stop( sprintf("`%s` must be one of %s", arg, paste0('"', options, '"', collapse = ", ")), call. = FALSE ) } result } s2/R/s2-predicates.R0000644000175000017510000001306614737212474013743 0ustar nileshnilesh #' S2 Geography Predicates #' #' These functions operate two geography vectors (pairwise), and return #' a logical vector. #' #' @inheritParams s2_is_collection #' @inheritParams s2_boundary #' @param distance A distance on the surface of the earth in the same units #' as `radius`. #' @param lng1,lat1,lng2,lat2 A latitude/longitude range #' @param detail The number of points with which to approximate #' non-geodesic edges. #' #' @inheritSection s2_options Model #' #' @export #' #' @seealso #' Matrix versions of these predicates (e.g., [s2_intersects_matrix()]). #' #' BigQuery's geography function reference: #' #' - [ST_CONTAINS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_contains) #' - [ST_COVEREDBY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_coveredby) #' - [ST_COVERS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_covers) #' - [ST_DISJOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_disjoint) #' - [ST_EQUALS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_equals) #' - [ST_INTERSECTS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersects) #' - [ST_INTERSECTSBOX](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersectsbox) #' - [ST_TOUCHES](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_touches) #' - [ST_WITHIN](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_within) #' - [ST_DWITHIN](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dwithin) #' #' @examples #' s2_contains( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_within( #' c("POINT (5 5)", "POINT (-1 1)"), #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))" #' ) #' #' s2_covered_by( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_covers( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_disjoint( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_intersects( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_equals( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' "POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0))", #' "POLYGON ((-1 -1, 10 0, 10 10, 0 10, -1 -1))" #' ) #' ) #' #' s2_intersects( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)") #' ) #' #' s2_intersects_box( #' c("POINT (5 5)", "POINT (-1 1)"), #' 0, 0, 10, 10 #' ) #' #' s2_touches( #' "POLYGON ((0 0, 0 1, 1 1, 0 0))", #' c("POINT (0 0)", "POINT (0.5 0.75)", "POINT (0 0.5)") #' ) #' #' s2_dwithin( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)"), #' 0 # distance in meters #' ) #' #' s2_dwithin( #' "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", #' c("POINT (5 5)", "POINT (-1 1)"), #' 1e6 # distance in meters #' ) #' s2_contains <- function(x, y, options = s2_options(model = "open")) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_contains(recycled[[1]], recycled[[2]], options) } #' @rdname s2_contains #' @export s2_within <- function(x, y, options = s2_options(model = "open")) { s2_contains(y, x, options) } #' @rdname s2_contains #' @export s2_covered_by <- function(x, y, options = s2_options(model = "closed")) { s2_covers(y, x, options) } #' @rdname s2_contains #' @export s2_covers <- function(x, y, options = s2_options(model = "closed")) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_contains(recycled[[1]], recycled[[2]], options) } #' @rdname s2_contains #' @export s2_disjoint <- function(x, y, options = s2_options()) { !s2_intersects(x, y, options) } #' @rdname s2_contains #' @export s2_intersects <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_intersects(recycled[[1]], recycled[[2]], options) } #' @rdname s2_contains #' @export s2_equals <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_equals(recycled[[1]], recycled[[2]], options) } #' @rdname s2_contains #' @export s2_intersects_box <- function(x, lng1, lat1, lng2, lat2, detail = 1000, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), lng1, lat1, lng2, lat2, detail) cpp_s2_intersects_box( recycled[[1]], recycled[[2]], recycled[[3]], recycled[[4]], recycled[[5]], detail = recycled[[6]], s2options = options ) } #' @rdname s2_contains #' @export s2_touches <- function(x, y, options = s2_options()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_touches(recycled[[1]], recycled[[2]], options) } #' @rdname s2_contains #' @export s2_dwithin <- function(x, y, distance, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), distance / radius) cpp_s2_dwithin(recycled[[1]], recycled[[2]], recycled[[3]]) } #' @rdname s2_contains #' @export s2_prepared_dwithin <- function(x, y, distance, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), distance / radius) cpp_s2_prepared_dwithin(recycled[[1]], recycled[[2]], recycled[[3]]) } s2/R/plot.R0000644000175000017510000000756314737212474012261 0ustar nileshnilesh #' Plot S2 Geographies #' #' @inheritParams wk::wk_plot #' @param plot_hemisphere Plot the outline of the earth #' @param centre The longitude/latitude point of the centre of the #' orthographic projection #' @param simplify Use `FALSE` to skip the simplification step #' #' @return The input, invisibly #' @export #' #' @examples #' s2_plot(s2_data_countries()) #' s2_plot(s2_data_cities(), add = TRUE) #' s2_plot <- function(x, ..., asp = 1, xlab = "", ylab = "", rule = "evenodd", add = FALSE, plot_hemisphere = FALSE, simplify = TRUE, centre = NULL) { x <- as_s2_geography(x) if (add) { last <- last_plot_env$centre centre <- if (is.null(last)) s2_lnglat(0, 0) else last } else if (is.null(centre)) { centre <- s2_centroid_agg(x, na.rm = TRUE) } centre <- as_s2_lnglat(centre) projection <- s2_projection_orthographic(centre) hemisphere_bounds_poly <- cap_to_polygon(centre, (pi / 2) - 1e-5) if (plot_hemisphere) { bbox_projected <- wk::rct(-1, -1, 1, 1) } else if (!add) { bbox_projected <- wk::wk_handle( x, wk::wk_bbox_handler(), s2_projection = projection, s2_tessellate_tol = s2_tessellate_tol_default() ) } wk::wk_plot( wk::xy(), bbox = bbox_projected, asp = asp, xlab = xlab, ylab = ylab, add = add ) if (!add) { last_plot_env$centre <- centre } if (plot_hemisphere) { wk::wk_plot(wk::crc(0, 0, 1), add = TRUE) } # estimate resolution. In user coords, this can be though of in radians # (at the centre of the plot) usr <- graphics::par("usr") usr_x <- usr[1:2] usr_y <- usr[3:4] device_x <- graphics::grconvertX(usr_x, to = "device") device_y <- graphics::grconvertY(usr_y, to = "device") scale_x <- diff(device_x) / diff(usr_x) scale_y <- diff(device_y) / diff(usr_y) scale <- min(abs(scale_x), abs(scale_y)) resolution_usr_rad <- 0.25 / scale # limit output to dimensions in input dimensions_in_input <- setdiff(unique(s2_dimension(x)), NA_character_) if (simplify) { x_hemisphere <- s2_intersection( x, hemisphere_bounds_poly, options = s2_options( snap = s2_snap_distance(resolution_usr_rad), snap_radius = resolution_usr_rad, simplify_edge_chains = TRUE, dimensions = c("point", "polyline", "polygon")[dimensions_in_input + 1] ) ) } else { x_hemisphere <- s2_intersection( x, hemisphere_bounds_poly, options = s2_options( dimensions = c("point", "polyline", "polygon")[dimensions_in_input + 1] ) ) } x_hemisphere[s2_is_empty(x_hemisphere)] <- as_s2_geography("POINT EMPTY") x_hemisphere_planar <- wk::wk_handle( x_hemisphere, wk::wkb_writer(), s2_projection = projection, # if this is too small we can get a stack overflow since the # tessellation is recursive s2_tessellate_tol = max(0.002, resolution_usr_rad * 4) ) wk::wk_plot( x_hemisphere_planar, ..., rule = rule, add = TRUE ) invisible(x) } #' @export plot.s2_geography <- function(x, ...) { s2_plot(x, ...) } #' @export plot.s2_cell_union <- function(x, ...) { s2_plot(x, ...) invisible(x) } #' @export plot.s2_cell <- function(x, ...) { if (all(s2_cell_is_leaf(x), na.rm = TRUE)) { s2_plot(s2_cell_center(x), ...) } else { s2_plot(s2_cell_polygon(x), ...) } invisible(x) } cap_to_polygon <- function(centre = s2_lnglat(0, 0), radius_rad) { centre <- as_s2_lnglat(centre) rad_proj <- sin(radius_rad) points <- wk::xy( c(0, rad_proj, 0, -rad_proj, 0), c(rad_proj, 0, -rad_proj, 0, rad_proj) ) points_s2 <- wk::wk_handle( points, s2_geography_writer( projection = s2_projection_orthographic(centre) ) ) s2_make_polygon(s2_x(points_s2), s2_y(points_s2)) } last_plot_env <- new.env(parent = emptyenv()) last_plot_env$centre <- NULL s2/R/s2-geography.R0000644000175000017510000001314714737212474013605 0ustar nileshnilesh #' Create an S2 Geography Vector #' #' Geography vectors are arrays of points, lines, polygons, and/or collections #' of these. Geography vectors assume coordinates are longitude and latitude #' on a perfect sphere. #' #' The coercion function [as_s2_geography()] is used to wrap the input #' of most functions in the s2 package so that you can use other objects with #' an unambiguious interpretation as a geography vector. Geography vectors #' have a minimal [vctrs][vctrs::vctrs-package] implementation, so you can #' use these objects in tibble, dplyr, and other packages that use the vctrs #' framework. #' #' @param x An object that can be converted to an s2_geography vector #' @param oriented TRUE if polygon ring directions are known to be correct #' (i.e., exterior rings are defined counter clockwise and interior #' rings are defined clockwise). #' @param check Use `check = FALSE` to skip error on invalid geometries #' @param ... Unused #' #' @return An object with class s2_geography #' @export #' #' @seealso #' [s2_geog_from_wkb()], [s2_geog_from_text()], [s2_geog_point()], #' [s2_make_line()], [s2_make_polygon()] for other ways to #' create geography vectors, and [s2_as_binary()] and [s2_as_text()] #' for other ways to export them. #' as_s2_geography <- function(x, ...) { UseMethod("as_s2_geography") } #' @rdname as_s2_geography #' @export s2_geography <- function() { new_s2_geography(list()) } #' @rdname as_s2_geography #' @export as_s2_geography.s2_geography <- function(x, ...) { x } #' @rdname as_s2_geography #' @export as_s2_geography.wk_xy <- function(x, ...) { x <- as_s2_lnglat(x) df <- unclass(x) s2_geog_point(df[[1]], df[[2]]) } #' @rdname as_s2_geography #' @export as_s2_geography.wk_wkb <- function(x, ..., oriented = FALSE, check = TRUE) { if (identical(wk::wk_is_geodesic(x), FALSE)) { # points and an empty vector are OK and shouldn't trigger an error meta <- wk::wk_meta(x) if (!all(meta$geometry_type %in% c(1, 4, NA), na.rm = TRUE)) { stop( paste0( "Can't create s2_geography from Cartesian wkb().\n", "Use `wk_set_geodesic(x, TRUE)` to assert that edges can be\n", "interpolated along the sphere." ), call. = FALSE ) } } wk::wk_handle( x, s2_geography_writer(oriented = oriented, check = check) ) } #' @rdname as_s2_geography #' @export as_s2_geography.WKB <- function(x, ..., oriented = FALSE, check = TRUE) { s2_geog_from_wkb(x, oriented = oriented, check = check) } #' @rdname as_s2_geography #' @export as_s2_geography.blob <- function(x, ..., oriented = FALSE, check = TRUE) { s2_geog_from_wkb(x, oriented = oriented, check = check) } #' @rdname as_s2_geography #' @export as_s2_geography.wk_wkt <- function(x, ..., oriented = FALSE, check = TRUE) { if (identical(wk::wk_is_geodesic(x), FALSE)) { # points and an empty vector are OK and shouldn't trigger an error meta <- wk::wk_meta(x) if (!all(meta$geometry_type %in% c(1, 4, NA), na.rm = TRUE)) { stop( paste0( "Can't create s2_geography from Cartesian wkt().\n", "Use `wk_set_geodesic(x, TRUE)` to assert that edges can be\n", "interpolated along the sphere." ), call. = FALSE ) } } wk::wk_handle( x, s2_geography_writer(oriented = oriented, check = check) ) } #' @rdname as_s2_geography #' @export as_s2_geography.character <- function(x, ..., oriented = FALSE, check = TRUE) { s2_geog_from_text(x, oriented = oriented, check = check) } #' @rdname as_s2_geography #' @export as_s2_geography.logical <- function(x, ...) { stopifnot(isTRUE(x)) new_s2_geography(s2_geography_full(TRUE)) } #' @importFrom wk as_wkb #' @rdname as_s2_geography #' @export as_wkb.s2_geography <- function(x, ...) { wkb <- wk::wk_handle(x, wk::wkb_writer()) wk::wk_is_geodesic(wkb) <- TRUE wk::wk_crs(wkb) <- wk::wk_crs_longlat() wkb } #' @importFrom wk as_wkt #' @rdname as_s2_geography #' @export as_wkt.s2_geography <- function(x, ...) { wkt <- wk::wk_handle(x, wk::wkt_writer()) wk::wk_is_geodesic(wkt) <- TRUE wk::wk_crs(wkt) <- wk::wk_crs_longlat() wkt } #' @importFrom wk wk_crs #' @export wk_crs.s2_geography <- function(x) { wk::wk_crs_longlat() } #' @importFrom wk wk_set_crs #' @export wk_set_crs.s2_geography <- function(x, crs) { if (!wk::wk_crs_equal(crs, wk::wk_crs(x))) { warning("Setting the crs of s2_geography() is not supported") } x } #' @importFrom wk wk_is_geodesic #' @export wk_is_geodesic.s2_geography <- function(x) { TRUE } #' @importFrom wk wk_set_geodesic #' @export wk_set_geodesic.s2_geography <- function(x, geodesic) { if (!isTRUE(geodesic)) { stop("Can't set geodesic of s2_geography to FALSE") } x } new_s2_geography <- function(x) { structure(x, class = c("s2_geography", "wk_vctr")) } #' @export is.na.s2_geography <- function(x) { cpp_s2_geography_is_na(x) } #' @export `[<-.s2_geography` <- function(x, i, value) { x <- unclass(x) x[i] <- as_s2_geography(value) new_s2_geography(x) } #' @export `[[<-.s2_geography` <- function(x, i, value) { x <- unclass(x) x[i] <- as_s2_geography(value) new_s2_geography(x) } #' @export format.s2_geography <- function(x, ..., max_coords = 5, precision = 9, trim = TRUE) { wk::wk_format(x, precision = precision, max_coords = max_coords, trim = trim) } # this is what gets called by the RStudio viewer, for which # format() is best suited (s2_as_text() is more explicit for WKT output) #' @export as.character.s2_geography <- function(x, ..., max_coords = 5, precision = 9, trim = TRUE) { format(x, ..., max_coords = max_coords, precision = precision, trim = trim) } s2/R/s2-package.R0000644000175000017510000000041714737212474013207 0ustar nileshnilesh#' @keywords internal "_PACKAGE" # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start #' @useDynLib s2, .registration = TRUE #' @importFrom Rcpp sourceCpp ## usethis namespace: end NULL s2/R/s2-point.R0000644000175000017510000000260314737212474012744 0ustar nileshnilesh #' Create an S2 Point Vector #' #' In S2 terminology, a "point" is a 3-dimensional unit vector representation #' of an [s2_point()]. Internally, all s2 objects are stored as #' 3-dimensional unit vectors. #' #' @param x,y,z Vectors of latitude and longitude values in degrees. #' @param ... Unused #' #' @return An object with class s2_point #' @export #' #' @examples #' point <- s2_lnglat(-64, 45) # Halifax, Nova Scotia! #' as_s2_point(point) #' as.data.frame(as_s2_point(point)) #' s2_point <- function(x, y, z) { wk::xyz(x, y, z, crs = s2_point_crs()) } #' @rdname s2_point #' @export s2_point_crs <- function() { structure(list(), class = "s2_point_crs") } #' @export format.s2_point_crs <- function(x, ...) { "s2_point_crs" } #' @rdname s2_point #' @export as_s2_point <- function(x, ...) { UseMethod("as_s2_point") } #' @rdname s2_point #' @export as_s2_point.default <- function(x, ...) { as_s2_point(wk::as_xy(x)) } #' @rdname s2_point #' @export as_s2_point.wk_xy <- function(x, ...) { stopifnot(wk::wk_crs_equal(wk::wk_crs(x), wk::wk_crs_longlat())) wk::new_wk_xyz( s2_point_from_s2_lnglat(x), crs = s2_point_crs() ) } #' @rdname s2_point #' @export as_s2_point.wk_xyz <- function(x, ...) { wk::wk_set_crs( wk::as_xy(x, dims = c("x", "y", "z")), s2_point_crs() ) } #' @export as_s2_point.character <- function(x, ...) { as_s2_point(wk::new_wk_wkt(x)) } s2/R/utils.R0000644000175000017510000000440514737212474012433 0ustar nileshnilesh new_data_frame <- function(x) { structure(x, row.names = c(NA, length(x[[1]])), class = "data.frame") } recycle_common <- function(...) { dots <- list(...) lengths <- vapply(dots, length, integer(1)) non_constant_lengths <- unique(lengths[lengths != 1]) if (length(non_constant_lengths) == 0) { final_length <- 1 } else if(length(non_constant_lengths) == 1) { final_length <- non_constant_lengths } else { lengths_label <- paste0(non_constant_lengths, collapse = ", ") stop(sprintf("Incompatible lengths: %s", lengths_label)) } lapply(dots, rep_len, final_length) } # The problems object is generated when building or processing an s2_geography(): # instead of attaching to the object as an attribute, this function is # called from Rcpp if there were any problems to format them in a # human-readable way. Theoretically one could change this to only warn # instead of stop (error values are set to NA/NULL). stop_problems_create <- function(feature_id, problem) { n <- length(feature_id) feature_label <- if (n != 1) "features" else "feature" stop_problems( feature_id, problem, sprintf("Found %d %s with invalid spherical geometry.", n, feature_label) ) } stop_problems_process <- function(feature_id, problem) { n <- length(feature_id) error_label <- if (n != 1) "errors" else "error" stop_problems( feature_id, problem, sprintf("Encountered %d processing %s.", n, error_label) ) } stop_problems <- function(feature_id, problem, header) { n <- length(feature_id) if (n > 10) { feature_id <- feature_id[1:10] problem <- problem[1:10] more <- sprintf("\n...and %s more", n - 10) } else { more <- "" } msg <- paste0( header, "\n", paste0("[", feature_id + 1, "] ", problem , collapse = "\n"), more ) stop(msg, call. = FALSE) } expect_wkt_equal <- function(x, y, precision = 16) { testthat::expect_equal( wk::wk_format( as_s2_geography(x), precision = precision, trim = TRUE, max_coords = .Machine$integer.max ), wk::wk_format( as_s2_geography(y), precision = precision, trim = TRUE, max_coords = .Machine$integer.max ) ) } expect_near <- function(x, y, epsilon) { testthat::expect_true(abs(y - x) < epsilon) } s2/R/s2-accessors.R0000644000175000017510000001306714737212474013606 0ustar nileshnilesh #' S2 Geography Accessors #' #' Accessors extract information about [geography vectors][as_s2_geography]. #' #' @param x,y [geography vectors][as_s2_geography]. These inputs #' are passed to [as_s2_geography()], so you can pass other objects #' (e.g., character vectors of well-known text) directly. #' @param radius Radius of the earth. Defaults to the average radius of #' the earth in meters as defined by [s2_earth_radius_meters()]. #' #' @export #' #' @seealso #' BigQuery's geography function reference: #' #' - [ST_ISCOLLECTION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_iscollection) #' - [ST_DIMENSION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dimension) #' - [ST_NUMPOINTS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_numpoints) #' - [ST_ISEMPTY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_isempty) #' - [ST_AREA](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area) #' - [ST_LENGTH](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_length) #' - [ST_PERIMETER](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_perimeter) #' - [ST_X](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_x) #' - [ST_Y](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_y) #' - [ST_DISTANCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_distance) #' - [ST_MAXDISTANCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_maxdistance) #' #' @examples #' # s2_is_collection() tests for multiple geometries in one feature #' s2_is_collection(c("POINT (-64 45)", "MULTIPOINT ((-64 45), (8 72))")) #' #' # s2_dimension() returns 0 for point, 1 for line, 2 for polygon #' s2_dimension( #' c( #' "GEOMETRYCOLLECTION EMPTY", #' "POINT (-64 45)", #' "LINESTRING (-64 45, 8 72)", #' "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", #' "GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 8 72))" #' ) #' ) #' #' # s2_num_points() counts points #' s2_num_points(c("POINT (-64 45)", "LINESTRING (-64 45, 8 72)")) #' #' # s2_is_empty tests for emptiness #' s2_is_empty(c("POINT (-64 45)", "POINT EMPTY")) #' #' # calculate area, length, and perimeter #' s2_area("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))") #' s2_perimeter("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))") #' s2_length(s2_boundary("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")) #' #' # extract x and y coordinates from points #' s2_x(c("POINT (-64 45)", "POINT EMPTY")) #' s2_y(c("POINT (-64 45)", "POINT EMPTY")) #' #' # calculate minimum and maximum distance between two geometries #' s2_distance( #' "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", #' "POINT (-64 45)" #' ) #' s2_max_distance( #' "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))", #' "POINT (-64 45)" #' ) #' s2_is_collection <- function(x) { cpp_s2_is_collection(as_s2_geography(x)) } #' @rdname s2_is_collection #' @export s2_is_valid <- function(x) { cpp_s2_is_valid(as_s2_geography(x, check = FALSE)) } #' @rdname s2_is_collection #' @export s2_is_valid_detail <- function(x) { x <- as_s2_geography(x, check = FALSE) data.frame( is_valid = cpp_s2_is_valid(x), reason = cpp_s2_is_valid_reason(x), stringsAsFactors = FALSE ) } #' @rdname s2_is_collection #' @export s2_dimension <- function(x) { cpp_s2_dimension(as_s2_geography(x)) } #' @rdname s2_is_collection #' @export s2_num_points <- function(x) { cpp_s2_num_points(as_s2_geography(x)) } #' @rdname s2_is_collection #' @export s2_is_empty <- function(x) { cpp_s2_is_empty(as_s2_geography(x)) } #' @rdname s2_is_collection #' @export s2_area <- function(x, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), radius) cpp_s2_area(recycled[[1]]) * radius ^ 2 } #' @rdname s2_is_collection #' @export s2_length <- function(x, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), radius) cpp_s2_length(recycled[[1]]) * radius } #' @rdname s2_is_collection #' @export s2_perimeter <- function(x, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), radius) cpp_s2_perimeter(recycled[[1]]) * radius } #' @rdname s2_is_collection #' @export s2_x <- function(x) { cpp_s2_x(as_s2_geography(x)) } #' @rdname s2_is_collection #' @export s2_y <- function(x) { cpp_s2_y(as_s2_geography(x)) } # document these with the other linear referencers #' @rdname s2_interpolate #' @export s2_project <- function(x, y, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius) length <- cpp_s2_length(recycled[[1]]) * radius cpp_s2_project_normalized(recycled[[1]], recycled[[2]]) * length } #' @rdname s2_interpolate #' @export s2_project_normalized <- function(x, y) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y)) cpp_s2_project_normalized(recycled[[1]], recycled[[2]]) } #' @rdname s2_is_collection #' @export s2_distance <- function(x, y, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius) cpp_s2_distance(recycled[[1]], recycled[[2]]) * radius } #' @rdname s2_is_collection #' @export s2_max_distance <- function(x, y, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius) cpp_s2_max_distance(recycled[[1]], recycled[[2]]) * radius } s2/R/s2-bounds.R0000644000175000017510000000235514737212474013111 0ustar nileshnilesh #' Compute feature-wise and aggregate bounds #' #' [s2_bounds_rect()] returns a bounding latitude-longitude #' rectangle that contains the region; [s2_bounds_cap()] returns a bounding circle #' represented by a centre point (lat, lng) and an angle. The bound may not be tight #' for points, polylines and geometry collections. The rectangle returned may depend on #' the order of points or polylines. `lng_lo` values larger than `lng_hi` indicate #' regions that span the antimeridian, see the Fiji example. #' #' @param x An [s2_geography()] vector. #' @export #' @return Both functions return a `data.frame`: #' #' - [s2_bounds_rect()]: Columns `minlng`, `minlat`, `maxlng`, `maxlat` (degrees) #' - [s2_bounds_cap()]: Columns `lng`, `lat`, `angle` (degrees) #' #' @examples #' s2_bounds_cap(s2_data_countries("Antarctica")) #' s2_bounds_cap(s2_data_countries("Netherlands")) #' s2_bounds_cap(s2_data_countries("Fiji")) #' #' s2_bounds_rect(s2_data_countries("Antarctica")) #' s2_bounds_rect(s2_data_countries("Netherlands")) #' s2_bounds_rect(s2_data_countries("Fiji")) #' s2_bounds_cap <- function(x) { cpp_s2_bounds_cap(as_s2_geography(x)) } #' @rdname s2_bounds_cap #' @export s2_bounds_rect <- function(x) { cpp_s2_bounds_rect(as_s2_geography(x)) } s2/R/s2-cell-union.R0000644000175000017510000001170014737212474013656 0ustar nileshnilesh #' Create S2 Cell Union vectors #' #' @param x A `list()` of [s2_cell()] vectors. #' @param ... Passed to S3 methods #' #' @return An object of class "s2_cell_union". #' @export #' s2_cell_union <- function(x = list()) { x <- as.list(x) input_na <- vapply(x, is.null, logical(1)) union <- vector("list", length(x)) union[input_na] <- list(NULL) union[!input_na] <- lapply(x[!input_na], as_s2_cell) new_s2_cell_union(union) } #' @rdname s2_cell_union #' @export as_s2_geography.s2_cell_union <- function(x, ...) { new_s2_geography(cpp_s2_geography_from_cell_union(as_s2_cell_union(x))) } #' @rdname s2_cell_union #' @export as_s2_cell_union <- function(x, ...) { UseMethod("as_s2_cell_union") } #' @rdname s2_cell_union #' @export as_s2_cell_union.s2_cell_union <- function(x, ...) { x } #' @rdname s2_cell_union #' @export as_s2_cell_union.s2_cell <- function(x, ...) { cpp_s2_cell_to_cell_union(x) } #' @rdname s2_cell_union #' @export as_s2_cell_union.character <- function(x, ...) { split <- strsplit(x, "\\s*;\\s*") split[is.na(x)] <- list(NULL) s2_cell_union(split) } new_s2_cell_union <- function(x) { stopifnot(typeof(x) == "list") structure(x, class = c("s2_cell_union", "wk_vctr")) } #' @export is.na.s2_cell_union <- function(x, ...) { cpp_s2_cell_union_is_na(x) } #' @export format.s2_cell_union <- function(x, ...) { formatted <- vapply( unclass(x), function(e) paste0(as.character(e), collapse = ";"), character(1) ) formatted[is.na(x)] <- "" formatted } #' @export as.character.s2_cell_union <- function(x, ...) { formatted <- vapply( unclass(x), function(e) paste0(as.character(e), collapse = ";"), character(1) ) formatted[is.na(x)] <- NA_character_ formatted } #' @export print.s2_cell_union <- function(x, ...) { utils::str(x, ...) invisible(x) } #' @method unlist s2_cell_union #' @export unlist.s2_cell_union <- function(x, recursive = TRUE, use.names = TRUE) { unlisted <- unlist(unclass(x), recursive = recursive, use.names = use.names) new_s2_cell(as.double(unlisted)) } #' @importFrom utils str #' @export str.s2_cell_union <- function(object, ..., indent.str = "") { cat(sprintf("%s\n%s", indent.str, length(object), indent.str)) str(unclass(object), ..., indent.str = indent.str) invisible(object) } #' S2 cell union operators #' #' @param x,y An [s2_geography][as_s2_geography] or [s2_cell_union()]. #' @param min_level,max_level The minimum and maximum levels to constrain the #' covering. #' @param max_cells The maximum number of cells in the covering. Defaults to #' 8. #' @param buffer A distance to buffer outside the geography #' @param interior Use `TRUE` to force the covering inside the geography. #' @inheritParams s2_cell_is_valid #' #' @export #' s2_cell_union_normalize <- function(x) { cpp_s2_cell_union_normalize(as_s2_cell_union(x)) } #' @rdname s2_cell_union_normalize #' @export s2_cell_union_contains <- function(x, y) { if (inherits(y, "s2_cell")) { recycled <- recycle_common(as_s2_cell_union(x), y) cpp_s2_cell_union_contains_cell(recycled[[1]], recycled[[2]]) } else { cpp_s2_cell_union_contains(as_s2_cell_union(x), as_s2_cell_union(y)) } } #' @rdname s2_cell_union_normalize #' @export s2_cell_union_intersects <- function(x, y) { cpp_s2_cell_union_intersects(as_s2_cell_union(x), as_s2_cell_union(y)) } #' @rdname s2_cell_union_normalize #' @export s2_cell_union_intersection <- function(x, y) { cpp_s2_cell_union_intersection(as_s2_cell_union(x), as_s2_cell_union(y)) } #' @rdname s2_cell_union_normalize #' @export s2_cell_union_union <- function(x, y) { cpp_s2_cell_union_union(as_s2_cell_union(x), as_s2_cell_union(y)) } #' @rdname s2_cell_union_normalize #' @export s2_cell_union_difference <- function(x, y) { cpp_s2_cell_union_difference(as_s2_cell_union(x), as_s2_cell_union(y)) } #' @rdname s2_cell_union_normalize #' @export s2_covering_cell_ids <- function(x, min_level = 0, max_level = 30, max_cells = 8, buffer = 0, interior = FALSE, radius = s2_earth_radius_meters()) { recycled <- recycle_common(as_s2_geography(x), buffer / radius) cpp_s2_covering_cell_ids( recycled[[1]], min_level, max_level, max_cells, recycled[[2]], interior ) } #' @rdname s2_cell_union_normalize #' @export s2_covering_cell_ids_agg <- function(x, min_level = 0, max_level = 30, max_cells = 8, buffer = 0, interior = FALSE, radius = s2_earth_radius_meters(), na.rm = FALSE) { distance <- as.numeric(buffer / radius) stopifnot(length(distance) == 1) if (is.na(distance)) { return(new_s2_cell_union(list(NULL))) } cpp_s2_covering_cell_ids_agg( as_s2_geography(x), min_level, max_level, max_cells, distance, interior, na.rm ) } s2/R/s2-cell.R0000644000175000017510000001771414737212474012543 0ustar nileshnilesh #' Create S2 Cell vectors #' #' The S2 cell indexing system forms the basis for spatial indexing #' in the S2 library. On their own, S2 cells can represent points #' or areas. As a union, a vector of S2 cells can approximate a #' line or polygon. These functions allow direct access to the #' S2 cell indexing system and are designed to have minimal overhead #' such that looping and recursion have acceptable performance #' when used within R code. #' #' Under the hood, S2 cell vectors are represented in R as vectors #' of type [double()]. This works because S2 cell identifiers are #' 64 bits wide, as are `double`s on all systems where R runs (The #' same trick is used by the bit64 package to represent signed #' 64-bit integers). As a happy accident, `NA_real_` is not a valid #' or meaningful cell identifier, so missing value support in the #' way R users might expect is preserved. It is worth noting that #' the underlying value of `s2_cell_sentinel()` would normally be #' considered `NA`; however, as it is meaningful and useful when #' programming with S2 cells, custom `is.na()` and comparison methods #' are implemented such that `s2_cell_sentinel()` is greater than #' all valid S2 cells and not considered missing. Users can and should #' implement compiled code that uses the underlying bytes of the #' vector, ensuring that the class of any returned object that should #' be interpreted in this way is constructed with `new_s2_cell()`. #' #' @param x The canonical S2 cell identifier as a character vector. #' @param ... Passed to methods #' #' @return An object of class s2_cell #' @export #' #' @examples #' s2_cell("4b59a0cd83b5de49") #' as_s2_cell(s2_lnglat(-64, 45)) #' as_s2_cell(s2_data_cities("Ottawa")) #' s2_cell <- function(x = character()) { new_s2_cell(cpp_s2_cell_from_string(x)) } #' @rdname s2_cell #' @export s2_cell_sentinel <- function() { cpp_s2_cell_sentinel() } #' @rdname s2_cell #' @export s2_cell_invalid <- function() { new_s2_cell(0) } #' @rdname s2_cell #' @export as_s2_cell <- function(x, ...) { UseMethod("as_s2_cell") } #' @rdname s2_cell #' @export as_s2_cell.s2_cell <- function(x, ...) { x } #' @rdname s2_cell #' @export as_s2_cell.character <- function(x, ...) { s2_cell(x) } #' @rdname s2_cell #' @export as_s2_cell.s2_geography <- function(x, ...) { cpp_s2_cell_from_lnglat(list(s2_x(x), s2_y(x))) } #' @rdname s2_cell #' @export as_s2_cell.wk_xy <- function(x, ...) { cpp_s2_cell_from_lnglat(as_s2_lnglat(x)) } #' @rdname s2_cell #' @export as_s2_cell.integer64 <- function(x, ...) { storage <- unclass(x) storage[is.na(x)] <- NA_real_ new_s2_cell(storage) } #' @rdname s2_cell #' @export new_s2_cell <- function(x) { stopifnot(is.double(x)) structure(x, class = c("s2_cell", "wk_vctr")) } # registered in zzz.R as.integer64.s2_cell <- function(x, ...) { # We store 64-bit integegers the same way bit64 does so we can just set the # class attribute and propagate NA values in the way that bit64 expects them. x_is_na <- is.na(x) class(x) <- "integer64" x[x_is_na] <- bit64::NA_integer64_ x } #' @export as.character.s2_cell <- function(x, ...) { cpp_s2_cell_to_string(x) } #' @export format.s2_cell <- function(x, ...) { format(as.character(x), quote = FALSE, ...) } #' @export as.list.s2_cell <- function(x, ...) { lapply(NextMethod(), new_s2_cell) } #' @export `[<-.s2_cell` <- function(x, i, value) { replacement <- as_s2_cell(value) x <- unclass(x) x[i] <- replacement new_s2_cell(x) } #' @export `[[<-.s2_cell` <- function(x, i, value) { x[i] <- value x } #' @export unique.s2_cell <- function(x, ...) { cpp_s2_cell_unique(x) } #' @export sort.s2_cell <- function(x, decreasing = FALSE, ...) { cpp_s2_cell_sort(x, decreasing) } #' @export is.na.s2_cell <- function(x) { cpp_s2_cell_is_na(x) } #' @export is.numeric.s2_cell <- function(x, ...) { FALSE } #' @export Ops.s2_cell <- function(e1, e2) { switch( .Generic, "==" = cpp_s2_cell_eq(e1, e2), "!=" = cpp_s2_cell_neq(e1, e2), "<" = cpp_s2_cell_lt(e1, e2), "<=" = cpp_s2_cell_lte(e1, e2), ">=" = cpp_s2_cell_gte(e1, e2), ">" = cpp_s2_cell_gt(e1, e2), stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE) ) } #' @export Math.s2_cell <- function(x, ...) { switch( .Generic, "cummax" = cpp_s2_cell_cummax(x), "cummin" = cpp_s2_cell_cummin(x), stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE) ) } #' @export Summary.s2_cell <- function(x, ..., na.rm = FALSE) { switch( .Generic, "min" = cpp_s2_cell_range(x, na.rm)[1], "max" = cpp_s2_cell_range(x, na.rm)[2], "range" = cpp_s2_cell_range(x, na.rm), stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE) ) } #' S2 cell operators #' #' @param x,y An [s2_cell()] vector #' @param level An integer between 0 and 30, inclusive. #' @param k An integer between 0 and 3 #' @param radius The radius to use (e.g., [s2_earth_radius_meters()]) #' @param na.rm Remove NAs prior to computing aggregate? #' @export #' s2_cell_is_valid <- function(x) { cpp_s2_cell_is_valid(x) } # exporters #' @rdname s2_cell_is_valid #' @export s2_cell_debug_string <- function(x) { cpp_s2_cell_debug_string(x) } #' @rdname s2_cell_is_valid #' @export s2_cell_to_lnglat <- function(x) { lnglat <- cpp_s2_cell_to_lnglat(x) s2_lnglat(lnglat[[1]], lnglat[[2]]) } #' @rdname s2_cell_is_valid #' @export s2_cell_center <- function(x) { cpp_s2_cell_center(x) } #' @rdname s2_cell_is_valid #' @export s2_cell_boundary <- function(x) { s2_boundary(cpp_s2_cell_polygon(x)) } #' @rdname s2_cell_is_valid #' @export s2_cell_polygon <- function(x) { cpp_s2_cell_polygon(x) } #' @rdname s2_cell_is_valid #' @export s2_cell_vertex <- function(x, k) { recycled <- recycle_common(x, k) cpp_s2_cell_vertex(recycled[[1]], recycled[[2]]) } # accessors #' @rdname s2_cell_is_valid #' @export s2_cell_level <- function(x) { cpp_s2_cell_level(x) } #' @rdname s2_cell_is_valid #' @export s2_cell_is_leaf <- function(x) { s2_cell_level(x) == 30L } #' @rdname s2_cell_is_valid #' @export s2_cell_is_face <- function(x) { s2_cell_level(x) == 0L } #' @rdname s2_cell_is_valid #' @export s2_cell_area <- function(x, radius = s2_earth_radius_meters()) { cpp_s2_cell_area(x) * radius ^ 2 } #' @rdname s2_cell_is_valid #' @export s2_cell_area_approx <- function(x, radius = s2_earth_radius_meters()) { cpp_s2_cell_area_approx(x) * radius ^ 2 } # transversers #' @rdname s2_cell_is_valid #' @export s2_cell_parent <- function(x, level = -1L) { recycled <- recycle_common(x, level) cpp_s2_cell_parent(recycled[[1]], recycled[[2]]) } #' @rdname s2_cell_is_valid #' @export s2_cell_child <- function(x, k) { recycled <- recycle_common(x, k) cpp_s2_cell_child(recycled[[1]], recycled[[2]]) } #' @rdname s2_cell_is_valid #' @export s2_cell_edge_neighbour <- function(x, k) { recycled <- recycle_common(x, k) cpp_s2_cell_edge_neighbour(recycled[[1]], recycled[[2]]) } # binary operators #' @rdname s2_cell_is_valid #' @export s2_cell_contains <- function(x, y) { cpp_s2_cell_contains(x, y) } #' @rdname s2_cell_is_valid #' @export s2_cell_distance <- function(x, y, radius = s2_earth_radius_meters()) { recycled <- recycle_common(x, y, radius) cpp_s2_cell_distance(recycled[[1]], recycled[[2]]) * radius } #' @rdname s2_cell_is_valid #' @export s2_cell_max_distance <- function(x, y, radius = s2_earth_radius_meters()) { recycled <- recycle_common(x, y, radius) cpp_s2_cell_max_distance(recycled[[1]], recycled[[2]]) * radius } #' @rdname s2_cell_is_valid #' @export s2_cell_may_intersect <- function(x, y) { cpp_s2_cell_may_intersect(x, y) } #' @rdname s2_cell_is_valid #' @export s2_cell_common_ancestor_level <- function(x, y) { cpp_s2_cell_common_ancestor_level(x, y) } #' @rdname s2_cell_is_valid #' @export s2_cell_common_ancestor_level_agg <- function(x, na.rm = FALSE) { x_na <- is.na(x) if (any(x_na) && !na.rm) { return(NA_integer_) } cpp_s2_cell_common_ancestor_level_agg(x[!x_na]) } s2/R/s2-earth.R0000644000175000017510000000120414737212474012712 0ustar nileshnilesh #' Earth Constants #' #' According to Yoder (1995), the radius of the earth is #' 6371.01 km. These functions are used to set the #' default radis for functions that return a distance #' or accept a distance as input #' (e.g., [s2_distance()] and [s2_dwithin()]). #' #' @export #' #' @references #' Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the #' Solar System" in Global Earth Physics, A Handbook of Physical Constants, #' AGU Reference Shelf 1, American Geophysical Union, Table 2. #' \doi{10.1029/RF001p0001} #' #' @examples #' s2_earth_radius_meters() #' s2_earth_radius_meters <- function() { 6371.01 * 1000 } s2/R/s2-lnglat.R0000644000175000017510000000251414737212474013075 0ustar nileshnilesh #' Create an S2 LngLat Vector #' #' This class represents a latitude and longitude on the Earth's surface. #' Most calculations in S2 convert this to a [as_s2_point()], which is a #' unit vector representation of this value. #' #' @param lat,lng Vectors of latitude and longitude values in degrees. #' @param x A [s2_lnglat()] vector or an object that can be coerced to one. #' @param ... Unused #' #' @return An object with class s2_lnglat #' @export #' #' @examples #' s2_lnglat(45, -64) # Halifax, Nova Scotia! #' as.data.frame(s2_lnglat(45, -64)) #' s2_lnglat <- function(lng, lat) { wk::xy(lng, lat, crs = wk::wk_crs_longlat()) } #' @rdname s2_lnglat #' @export as_s2_lnglat <- function(x, ...) { UseMethod("as_s2_lnglat") } #' @rdname s2_lnglat #' @export as_s2_lnglat.default <- function(x, ...) { as_s2_lnglat(wk::as_xy(x)) } #' @rdname s2_lnglat #' @export as_s2_lnglat.wk_xy <- function(x, ...) { wk::wk_set_crs( wk::as_xy(x, dims = c("x", "y")), wk::wk_crs_longlat() ) } #' @rdname s2_lnglat #' @export as_s2_lnglat.wk_xyz <- function(x, ...) { if (wk::wk_crs_equal(wk::wk_crs(x), s2_point_crs())) { wk::new_wk_xy( s2_lnglat_from_s2_point(x), crs = wk::wk_crs_longlat() ) } else { NextMethod() } } #' @export as_s2_lnglat.character <- function(x, ...) { as_s2_lnglat(wk::new_wk_wkt(x)) } s2/R/zzz.R0000644000175000017510000000340714737212474012131 0ustar nileshnilesh # nocov start .onLoad <- function(...) { # call c++ init cpp_s2_init() # dynamically register vctrs dependencies for (cls in c("s2_geography", "s2_cell", "s2_cell_union")) { s3_register("vctrs::vec_proxy", cls) s3_register("vctrs::vec_restore", cls) s3_register("vctrs::vec_ptype_abbr", cls) } s3_register("bit64::as.integer64", "s2_cell") } s3_register <- function(generic, class, method = NULL) { stopifnot(is.character(generic), length(generic) == 1) stopifnot(is.character(class), length(class) == 1) pieces <- strsplit(generic, "::")[[1]] stopifnot(length(pieces) == 2) package <- pieces[[1]] generic <- pieces[[2]] caller <- parent.frame() get_method_env <- function() { top <- topenv(caller) if (isNamespace(top)) { asNamespace(environmentName(top)) } else { caller } } get_method <- function(method, env) { if (is.null(method)) { get(paste0(generic, ".", class), envir = get_method_env()) } else { method } } method_fn <- get_method(method) stopifnot(is.function(method_fn)) # Always register hook in case package is later unloaded & reloaded setHook( packageEvent(package, "onLoad"), function(...) { ns <- asNamespace(package) # Refresh the method, it might have been updated by `devtools::load_all()` method_fn <- get_method(method) registerS3method(generic, class, method_fn, envir = ns) } ) # Avoid registration failures during loading (pkgload or regular) if (!isNamespaceLoaded(package)) { return(invisible()) } envir <- asNamespace(package) # Only register if generic can be accessed if (exists(generic, envir)) { registerS3method(generic, class, method_fn, envir = envir) } invisible() } # nocov end s2/R/s2-constructors-formatters.R0000644000175000017510000001510514737212474016550 0ustar nileshnilesh #' Create and Format Geography Vectors #' #' These functions create and export [geography vectors][as_s2_geography]. #' Unlike the BigQuery geography constructors, these functions do not sanitize #' invalid or redundant input using [s2_union()]. Note that when creating polygons #' using [s2_make_polygon()], rings can be open or closed. #' #' @inheritParams s2_is_collection #' @inheritParams as_s2_geography #' @param precision The number of significant digits to export when #' writing well-known text. If `trim = FALSE`, the number of #' digits after the decimal place. #' @param trim Should trailing zeroes be included after the decimal place? #' @param endian The endian-ness of the well-known binary. See [wk::wkb_translate_wkb()]. #' @param longitude,latitude Vectors of latitude and longitude #' @param wkt_string Well-known text #' @param wkb_bytes A `list()` of `raw()` #' @param planar Use `TRUE` to force planar edges in import or export. #' @param tessellate_tol_m The maximum number of meters to that a point must #' be moved to satisfy the planar edge constraint. #' @param feature_id,ring_id Vectors for which a change in #' sequential values indicates a new feature or ring. Use [factor()] #' to convert from a character vector. #' #' @export #' #' @seealso #' See [as_s2_geography()] for other ways to construct geography vectors. #' #' BigQuery's geography function reference: #' #' - [ST_GEOGPOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogpoint) #' - [ST_MAKELINE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makeline) #' - [ST_MAKEPOLYGON](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makepolygon) #' - [ST_GEOGFROMTEXT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromtext) #' - [ST_GEOGFROMWKB](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromwkb) #' - [ST_ASTEXT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_astext) #' - [ST_ASBINARY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_asbinary) #' #' @examples #' # create point geographies using coordinate values: #' s2_geog_point(-64, 45) #' #' # create line geographies using coordinate values: #' s2_make_line(c(-64, 8), c(45, 71)) #' #' # optionally, separate features using feature_id: #' s2_make_line( #' c(-64, 8, -27, -27), c(45, 71, 0, 45), #' feature_id = c(1, 1, 2, 2) #' ) #' #' # create polygon geographies using coordinate values: #' # (rings can be open or closed) #' s2_make_polygon(c(-45, 8, 0), c(64, 71, 90)) #' #' # optionally, separate rings and/or features using #' # ring_id and/or feature_id #' s2_make_polygon( #' c(20, 10, 10, 30, 45, 30, 20, 20, 40, 20, 45), #' c(35, 30, 10, 5, 20, 20, 15, 25, 40, 45, 30), #' feature_id = c(rep(1, 8), rep(2, 3)), #' ring_id = c(1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1) #' ) #' #' # import and export well-known text #' (geog <- s2_geog_from_text("POINT (-64 45)")) #' s2_as_text(geog) #' #' # import and export well-known binary #' (geog <- s2_geog_from_wkb(wk::as_wkb("POINT (-64 45)"))) #' s2_as_binary(geog) #' #' # import geometry from planar space #' s2_geog_from_text( #' "POLYGON ((0 0, 1 0, 0 1, 0 0))", #' planar = TRUE, #' tessellate_tol_m = 1 #' ) #' #' # export geographies into planar space #' geog <- s2_make_polygon(c(179, -179, 179), c(10, 10, 11)) #' s2_as_text(geog, planar = TRUE) #' #' # polygons containing a pole need an extra step #' geog <- s2_data_countries("Antarctica") #' geom <- s2_as_text( #' s2_intersection(geog, s2_world_plate_carree()), #' planar = TRUE #' ) #' s2_geog_point <- function(longitude, latitude) { wk::wk_handle(wk::xy(longitude, latitude), s2_geography_writer()) } #' @rdname s2_geog_point #' @export s2_make_line <- function(longitude, latitude, feature_id = 1L) { wk::wk_handle( wk::xy(longitude, latitude), wk::wk_linestring_filter( s2_geography_writer(), feature_id = as.integer(feature_id) ) ) } #' @rdname s2_geog_point #' @export s2_make_polygon <- function(longitude, latitude, feature_id = 1L, ring_id = 1L, oriented = FALSE, check = TRUE) { wk::wk_handle( wk::xy(longitude, latitude), wk::wk_polygon_filter( s2_geography_writer(oriented = oriented, check = check), feature_id = as.integer(feature_id), ring_id = as.integer(ring_id) ) ) } #' @rdname s2_geog_point #' @export s2_geog_from_text <- function(wkt_string, oriented = FALSE, check = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default()) { attributes(wkt_string) <- NULL wkt <- wk::new_wk_wkt(wkt_string, geodesic = TRUE) wk::validate_wk_wkt(wkt) wk::wk_handle( wkt, s2_geography_writer( oriented = oriented, check = check, tessellate_tol = if (planar) { tessellate_tol_m / s2_earth_radius_meters() } else { Inf } ) ) } #' @rdname s2_geog_point #' @export s2_geog_from_wkb <- function(wkb_bytes, oriented = FALSE, check = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default()) { attributes(wkb_bytes) <- NULL wkb <- wk::new_wk_wkb(wkb_bytes) wk::validate_wk_wkb(wkb) wk::wk_handle( wkb, s2_geography_writer( oriented = oriented, check = check, tessellate_tol = if (planar) { tessellate_tol_m / s2_earth_radius_meters() } else { Inf } ) ) } #' @rdname s2_geog_point #' @export s2_as_text <- function(x, precision = 16, trim = TRUE, planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default()) { wkt <- wk::wk_handle( as_s2_geography(x), wk::wkt_writer(precision = precision, trim = trim), s2_tessellate_tol = if (planar) { tessellate_tol_m / s2_earth_radius_meters() } else { Inf } ) attributes(wkt) <- NULL wkt } #' @rdname s2_geog_point #' @export s2_as_binary <- function(x, endian = wk::wk_platform_endian(), planar = FALSE, tessellate_tol_m = s2_tessellate_tol_default()) { structure( wk::wk_handle( as_s2_geography(x), wk::wkb_writer(endian = endian), s2_tessellate_tol = if (planar) { tessellate_tol_m / s2_earth_radius_meters() } else { Inf } ), class = "blob" ) } #' @rdname s2_geog_point #' @export s2_tessellate_tol_default <- function() { 100 } s2/tools/0000755000175000017510000000000015014104735012071 5ustar nileshnileshs2/tools/winlibs.R0000644000175000017510000000177714737212474013712 0ustar nileshnilesh # This script is used to support R 4.0, 4.1, and 4.2 on Windows, which do not have # OpenSSL available via pkg-config. It places the headers in windows/openssl/include # and the libs for this R version/arch in windows/openssl/lib to simplify the # configure/makevars setup. openssl_version <- "1.1.1k" if(file.exists("windows/openssl/include/openssl/ssl.h")) { cat("Using previously downloaded rwinlibs openssl") } else { cat(sprintf("Downloading OpenSSL %s from rwinlibs", openssl_version)) download.file(sprintf("https://github.com/rwinlib/openssl/archive/v%s.zip", openssl_version), "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "windows") file.rename("windows/openssl-1.1.1k", "windows/openssl") crt <- if (packageVersion("base") >= "4.2.0") "-ucrt" else "" libs <- list.files( sprintf("windows/openssl/lib/%s%s", .Platform$r_arch, crt), full.names = TRUE ) file.copy(libs, "windows/openssl/lib") unlink("lib.zip") } s2/tools/build_absl.sh0000755000175000017510000000334314737212474014546 0ustar nileshnilesh # https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Using-cmake : ${R_HOME=`R RHOME`} if test -z "${R_HOME}"; then echo "could not determine R_HOME" exit 1 fi # Do our best to pass on the user MAKEFLAGS. This can result in much faster # compilation of the vendored library. MAKEFLAGS=`${R_HOME}/bin/Rscript -e 'readRenviron("~/.R/Makevars"); cat(Sys.getenv("MAKEFLAGS"))'` if test -z "$MAKE"; then MAKE="`which make`"; fi if ${MAKE} --version ; then echo "Using MAKE=$MAKE $MAKEFLAGS" else echo "make not found" exit 1 fi if test -z "$CMAKE"; then CMAKE="`which cmake`"; fi if test -z "$CMAKE"; then CMAKE=/Applications/CMake.app/Contents/bin/cmake; fi if "${CMAKE}" --version ; then echo "Using CMAKE=$CMAKE" echo "Using MAKE=$MAKE $MAKEFLAGS" else echo "cmake not found" exit 1 fi CC=`"${R_HOME}/bin/R" CMD config CC` CXX="`${R_HOME}/bin/R CMD config CXX17` `${R_HOME}/bin/R CMD config CXX17STD`" CFLAGS=`"${R_HOME}/bin/R" CMD config CFLAGS` R_CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS` R_CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXX17FLAGS` LDFLAGS=`"${R_HOME}/bin/R" CMD config LDFLAGS` CMAKE_INSTALL_PREFIX="$1" if [ ! -d "tools/build/abseil-cpp" ]; then mkdir -p "tools/build/abseil-cpp" fi cd "tools/build/abseil-cpp" "${CMAKE}" \ -G "Unix Makefiles" \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_COLOR_MAKEFILE=OFF \ -DCMAKE_CXX_FLAGS_RELEASE="${R_CPPFLAGS} ${R_CXXFLAGS} ${WIN_CPPFLAGS}" \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ -DCMAKE_INSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}" \ -DCMAKE_CXX_STANDARD=17 \ -DABSL_PROPAGATE_CXX_STD=ON \ "../../vendor/abseil-cpp" && ${MAKE} ${MAKEFLAGS} && "${CMAKE}" --install . cd ../../.. s2/tools/docker/0000755000175000017510000000000015010321446013334 5ustar nileshnileshs2/tools/docker/fedora.dockerfile0000644000175000017510000000061014737212474016641 0ustar nileshnilesh ARG IMAGE=fedora:latest FROM ${IMAGE} RUN dnf install -y R cmake abseil-cpp-devel openssl-devel # Make sure we can use all cores to install things RUN mkdir ~/.R && echo "MAKEFLAGS = -j$(nproc)" > ~/.R/Makevars RUN R -e 'install.packages(c("wk", "bit64", "Rcpp", "testthat"), repos = "https://cloud.r-project.org")' CMD R CMD INSTALL /s2 --preclean && R -e 'testthat::test_local("/s2")' s2/tools/docker/alpine.dockerfile0000644000175000017510000000056614737212474016663 0ustar nileshnilesh ARG IMAGE=alpine:latest FROM ${IMAGE} RUN apk add bash R R-dev abseil-cpp-dev # Make sure we can use all cores to install things RUN mkdir ~/.R && echo "MAKEFLAGS = -j$(nproc)" > ~/.R/Makevars RUN R -e 'install.packages(c("wk", "bit64", "Rcpp", "testthat"), repos = "https://cloud.r-project.org")' CMD R CMD INSTALL /s2 --preclean && R -e 'testthat::test_local("/s2")' s2/tools/docker/debian-clang.dockerfile0000644000175000017510000000146215010321446017674 0ustar nileshnilesh ARG IMAGE=debian:testing FROM ${IMAGE} RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ r-base cmake libcurl4-openssl-dev libssl-dev clang-19 # Not all versions of ubuntu/debian have libabsl-dev RUN apt-get install -y libabsl-dev || true # Make sure we can use all cores to install things RUN mkdir ~/.R && echo "MAKEFLAGS = -j$(nproc)" > ~/.R/Makevars # Use clang if that's what we're up to. Probably not complete # (e.g., doesn't consider C++11 or 14 or 20 or 23 compilers) RUN echo "CC=clang-19" >> ~/.R/Makevars RUN echo "CXX=clang++-19" >> ~/.R/Makevars RUN echo "CXX17=clang++-19" >> ~/.R/Makevars RUN R -e 'install.packages(c("wk", "bit64", "Rcpp", "testthat"), repos = "https://cloud.r-project.org")' CMD R CMD INSTALL /s2 --preclean && R -e 'testthat::test_local("/s2")' s2/tools/docker/debian.dockerfile0000644000175000017510000000105314737212474016625 0ustar nileshnilesh ARG IMAGE=debian:testing FROM ${IMAGE} RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ r-base cmake libcurl4-openssl-dev libssl-dev # Not all versions of ubuntu/debian have libabsl-dev RUN apt-get install -y libabsl-dev || true # Make sure we can use all cores to install things RUN mkdir ~/.R && echo "MAKEFLAGS = -j$(nproc)" > ~/.R/Makevars RUN R -e 'install.packages(c("wk", "bit64", "Rcpp", "testthat"), repos = "https://cloud.r-project.org")' CMD R CMD INSTALL /s2 --preclean && R -e 'testthat::test_local("/s2")' s2/tools/test_openssl.c0000644000175000017510000000015514737212474014773 0ustar nileshnilesh#include #if OPENSSL_VERSION_NUMBER < 0x10000000L #error OpenSSL version too old #endif s2/tools/vendor/0000755000175000017510000000000014737212474013401 5ustar nileshnileshs2/tools/vendor/abseil-cpp/0000755000175000017510000000000015014104735015405 5ustar nileshnileshs2/tools/vendor/abseil-cpp/LICENSE0000644000175000017510000002614114737212474016431 0ustar nileshnilesh Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. s2/tools/vendor/abseil-cpp/absl/0000755000175000017510000000000014737212474016341 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/crc/0000755000175000017510000000000014737212474017110 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/crc/crc32c.h0000644000175000017510000001613214737212474020343 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: crc32c.h // ----------------------------------------------------------------------------- // // This header file defines the API for computing CRC32C values as checksums // for arbitrary sequences of bytes provided as a string buffer. // // The API includes the basic functions for computing such CRC32C values and // some utility functions for performing more efficient mathematical // computations using an existing checksum. #ifndef ABSL_CRC_CRC32C_H_ #define ABSL_CRC_CRC32C_H_ #include #include #include "absl/crc/internal/crc32c_inline.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN //----------------------------------------------------------------------------- // crc32c_t //----------------------------------------------------------------------------- // `crc32c_t` defines a strongly-typed integer for holding a CRC32C value. // // Some operators are intentionally omitted. Only equality operators are defined // so that `crc32c_t` can be directly compared. Methods for putting `crc32c_t` // directly into a set are omitted because this is bug-prone due to checksum // collisions. Use an explicit conversion to the `uint32_t` space for operations // that treat `crc32c_t` as an integer. class crc32c_t final { public: crc32c_t() = default; constexpr explicit crc32c_t(uint32_t crc) : crc_(crc) {} crc32c_t(const crc32c_t&) = default; crc32c_t& operator=(const crc32c_t&) = default; explicit operator uint32_t() const { return crc_; } friend bool operator==(crc32c_t lhs, crc32c_t rhs) { return static_cast(lhs) == static_cast(rhs); } friend bool operator!=(crc32c_t lhs, crc32c_t rhs) { return !(lhs == rhs); } template friend void AbslStringify(Sink& sink, crc32c_t crc) { absl::Format(&sink, "%08x", static_cast(crc)); } private: uint32_t crc_; }; namespace crc_internal { // Non-inline code path for `absl::ExtendCrc32c()`. Do not call directly. // Call `absl::ExtendCrc32c()` (defined below) instead. crc32c_t ExtendCrc32cInternal(crc32c_t initial_crc, absl::string_view buf_to_add); } // namespace crc_internal // ----------------------------------------------------------------------------- // CRC32C Computation Functions // ----------------------------------------------------------------------------- // ComputeCrc32c() // // Returns the CRC32C value of the provided string. crc32c_t ComputeCrc32c(absl::string_view buf); // ExtendCrc32c() // // Computes a CRC32C value from an `initial_crc` CRC32C value including the // `buf_to_add` bytes of an additional buffer. Using this function is more // efficient than computing a CRC32C value for the combined buffer from // scratch. // // Note: `ExtendCrc32c` with an initial_crc of 0 is equivalent to // `ComputeCrc32c`. // // This operation has a runtime cost of O(`buf_to_add.size()`) inline crc32c_t ExtendCrc32c(crc32c_t initial_crc, absl::string_view buf_to_add) { // Approximately 75% of calls have size <= 64. if (buf_to_add.size() <= 64) { uint32_t crc = static_cast(initial_crc); if (crc_internal::ExtendCrc32cInline(&crc, buf_to_add.data(), buf_to_add.size())) { return crc32c_t{crc}; } } return crc_internal::ExtendCrc32cInternal(initial_crc, buf_to_add); } // ExtendCrc32cByZeroes() // // Computes a CRC32C value for a buffer with an `initial_crc` CRC32C value, // where `length` bytes with a value of 0 are appended to the buffer. Using this // function is more efficient than computing a CRC32C value for the combined // buffer from scratch. // // This operation has a runtime cost of O(log(`length`)) crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length); // MemcpyCrc32c() // // Copies `src` to `dest` using `memcpy()` semantics, returning the CRC32C // value of the copied buffer. // // Using `MemcpyCrc32c()` is potentially faster than performing the `memcpy()` // and `ComputeCrc32c()` operations separately. crc32c_t MemcpyCrc32c(void* dest, const void* src, size_t count, crc32c_t initial_crc = crc32c_t{0}); // ----------------------------------------------------------------------------- // CRC32C Arithmetic Functions // ----------------------------------------------------------------------------- // The following functions perform arithmetic on CRC32C values, which are // generally more efficient than recalculating any given result's CRC32C value. // ConcatCrc32c() // // Calculates the CRC32C value of two buffers with known CRC32C values // concatenated together. // // Given a buffer with CRC32C value `crc1` and a buffer with // CRC32C value `crc2` and length, `crc2_length`, returns the CRC32C value of // the concatenation of these two buffers. // // This operation has a runtime cost of O(log(`crc2_length`)). crc32c_t ConcatCrc32c(crc32c_t crc1, crc32c_t crc2, size_t crc2_length); // RemoveCrc32cPrefix() // // Calculates the CRC32C value of an existing buffer with a series of bytes // (the prefix) removed from the beginning of that buffer. // // Given the CRC32C value of an existing buffer, `full_string_crc`; The CRC32C // value of a prefix of that buffer, `prefix_crc`; and the length of the buffer // with the prefix removed, `remaining_string_length` , return the CRC32C // value of the buffer with the prefix removed. // // This operation has a runtime cost of O(log(`remaining_string_length`)). crc32c_t RemoveCrc32cPrefix(crc32c_t prefix_crc, crc32c_t full_string_crc, size_t remaining_string_length); // RemoveCrc32cSuffix() // // Calculates the CRC32C value of an existing buffer with a series of bytes // (the suffix) removed from the end of that buffer. // // Given a CRC32C value of an existing buffer `full_string_crc`, the CRC32C // value of the suffix to remove `suffix_crc`, and the length of that suffix // `suffix_len`, returns the CRC32C value of the buffer with suffix removed. // // This operation has a runtime cost of O(log(`suffix_len`)) crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc, size_t suffix_length); // operator<< // // Streams the CRC32C value `crc` to the stream `os`. inline std::ostream& operator<<(std::ostream& os, crc32c_t crc) { return os << absl::StreamFormat("%08x", static_cast(crc)); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_CRC32C_H_ s2/tools/vendor/abseil-cpp/absl/crc/BUILD.bazel0000644000175000017510000001241114737212474020765 0ustar nileshnilesh# Copyright 2022 The Abseil Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) package(default_visibility = ["//visibility:private"]) licenses(["notice"]) cc_library( name = "cpu_detect", srcs = [ "internal/cpu_detect.cc", ], hdrs = ["internal/cpu_detect.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ "//absl/base", "//absl/base:config", ], ) cc_library( name = "crc_internal", srcs = [ "internal/crc.cc", "internal/crc_internal.h", "internal/crc_x86_arm_combined.cc", ], hdrs = [ "internal/crc.h", "internal/crc32_x86_arm_combined_simd.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":cpu_detect", "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/base:endian", "//absl/base:prefetch", "//absl/base:raw_logging_internal", "//absl/memory", "//absl/numeric:bits", ], ) cc_library( name = "crc32c", srcs = [ "crc32c.cc", "internal/crc32c_inline.h", "internal/crc_memcpy_fallback.cc", "internal/crc_memcpy_x86_64.cc", "internal/crc_non_temporal_memcpy.cc", ], hdrs = [ "crc32c.h", "internal/crc32c.h", "internal/crc_memcpy.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:public"], deps = [ ":cpu_detect", ":crc_internal", ":non_temporal_memcpy", "//absl/base:config", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/base:endian", "//absl/base:prefetch", "//absl/strings", "//absl/strings:str_format", ], ) cc_test( name = "crc32c_test", srcs = ["crc32c_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":crc32c", "//absl/strings", "//absl/strings:str_format", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "non_temporal_arm_intrinsics", hdrs = ["internal/non_temporal_arm_intrinsics.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ "//absl/base:config", ], ) cc_library( name = "non_temporal_memcpy", hdrs = ["internal/non_temporal_memcpy.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":non_temporal_arm_intrinsics", "//absl/base:config", "//absl/base:core_headers", ], ) cc_test( name = "crc_memcpy_test", size = "large", srcs = ["internal/crc_memcpy_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, shard_count = 3, visibility = ["//visibility:private"], deps = [ ":crc32c", "//absl/memory", "//absl/random", "//absl/random:distributions", "//absl/strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "non_temporal_memcpy_test", srcs = ["internal/non_temporal_memcpy_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":non_temporal_memcpy", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "crc_cord_state", srcs = ["internal/crc_cord_state.cc"], hdrs = ["internal/crc_cord_state.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//absl/strings:__pkg__"], deps = [ ":crc32c", "//absl/base:config", "//absl/numeric:bits", "//absl/strings", ], ) cc_test( name = "crc_cord_state_test", srcs = ["internal/crc_cord_state_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":crc32c", ":crc_cord_state", "@com_google_googletest//:gtest_main", ], ) cc_binary( name = "crc32c_benchmark", testonly = 1, srcs = ["crc32c_benchmark.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ "benchmark", ], visibility = ["//visibility:private"], deps = [ ":crc32c", "//absl/memory", "//absl/strings", "@com_github_google_benchmark//:benchmark_main", ], ) s2/tools/vendor/abseil-cpp/absl/crc/internal/0000755000175000017510000000000014737212474020724 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/crc/internal/crc_cord_state.h0000644000175000017510000001336114737212474024057 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ #define ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ #include #include #include #include "absl/base/config.h" #include "absl/crc/crc32c.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // CrcCordState is a copy-on-write class that holds the chunked CRC32C data // that allows CrcCord to perform efficient substring operations. CrcCordState // is used as a member variable in CrcCord. When a CrcCord is converted to a // Cord, the CrcCordState is shallow-copied into the root node of the Cord. If // the converted Cord is modified outside of CrcCord, the CrcCordState is // discarded from the Cord. If the Cord is converted back to a CrcCord, and the // Cord is still carrying the CrcCordState in its root node, the CrcCord can // re-use the CrcCordState, making the construction of the CrcCord cheap. // // CrcCordState does not try to encapsulate the CRC32C state (CrcCord requires // knowledge of how CrcCordState represents the CRC32C state). It does // encapsulate the copy-on-write nature of the state. class CrcCordState { public: // Constructors. CrcCordState(); CrcCordState(const CrcCordState&); CrcCordState(CrcCordState&&); // Destructor. Atomically unreferences the data. ~CrcCordState(); // Copy and move operators. CrcCordState& operator=(const CrcCordState&); CrcCordState& operator=(CrcCordState&&); // A (length, crc) pair. struct PrefixCrc { PrefixCrc() = default; PrefixCrc(size_t length_arg, absl::crc32c_t crc_arg) : length(length_arg), crc(crc_arg) {} size_t length = 0; // TODO(absl-team): Memory stomping often zeros out memory. If this struct // gets overwritten, we could end up with {0, 0}, which is the correct CRC // for a string of length 0. Consider storing a scrambled value and // unscrambling it before verifying it. absl::crc32c_t crc = absl::crc32c_t{0}; }; // The representation of the chunked CRC32C data. struct Rep { // `removed_prefix` is the crc and length of any prefix that has been // removed from the Cord (for example, by calling // `CrcCord::RemovePrefix()`). To get the checksum of any prefix of the // cord, this value must be subtracted from `prefix_crc`. See `Checksum()` // for an example. // // CrcCordState is said to be "normalized" if removed_prefix.length == 0. PrefixCrc removed_prefix; // A deque of (length, crc) pairs, representing length and crc of a prefix // of the Cord, before removed_prefix has been subtracted. The lengths of // the prefixes are stored in increasing order. If the Cord is not empty, // the last value in deque is the contains the CRC32C of the entire Cord // when removed_prefix is subtracted from it. std::deque prefix_crc; }; // Returns a reference to the representation of the chunked CRC32C data. const Rep& rep() const { return refcounted_rep_->rep; } // Returns a mutable reference to the representation of the chunked CRC32C // data. Calling this function will copy the data if another instance also // holds a reference to the data, so it is important to call rep() instead if // the data may not be mutated. Rep* mutable_rep() { if (refcounted_rep_->count.load(std::memory_order_acquire) != 1) { RefcountedRep* copy = new RefcountedRep; copy->rep = refcounted_rep_->rep; Unref(refcounted_rep_); refcounted_rep_ = copy; } return &refcounted_rep_->rep; } // Returns the CRC32C of the entire Cord. absl::crc32c_t Checksum() const; // Returns true if the chunked CRC32C cached is normalized. bool IsNormalized() const { return rep().removed_prefix.length == 0; } // Normalizes the chunked CRC32C checksum cache by subtracting any removed // prefix from the chunks. void Normalize(); // Returns the number of cached chunks. size_t NumChunks() const { return rep().prefix_crc.size(); } // Helper that returns the (length, crc) of the `n`-th cached chunked. PrefixCrc NormalizedPrefixCrcAtNthChunk(size_t n) const; // Poisons all chunks to so that Checksum() will likely be incorrect with high // probability. void Poison(); private: struct RefcountedRep { std::atomic count{1}; Rep rep; }; // Adds a reference to the shared global empty `RefcountedRep`, and returns a // pointer to the `RefcountedRep`. This is an optimization to avoid unneeded // allocations when the allocation is unlikely to ever be used. The returned // pointer can be `Unref()`ed when it is no longer needed. Since the returned // instance will always have a reference counter greater than 1, attempts to // modify it (by calling `mutable_rep()`) will create a new unshared copy. static RefcountedRep* RefSharedEmptyRep(); static void Ref(RefcountedRep* r) { assert(r != nullptr); r->count.fetch_add(1, std::memory_order_relaxed); } static void Unref(RefcountedRep* r) { assert(r != nullptr); if (r->count.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete r; } } RefcountedRep* refcounted_rep_; }; } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC_CORD_STATE_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc0000644000175000017510000007163214737212474025217 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Hardware accelerated CRC32 computation on Intel and ARM architecture. #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/dynamic_annotations.h" #include "absl/base/internal/endian.h" #include "absl/base/prefetch.h" #include "absl/crc/internal/cpu_detect.h" #include "absl/crc/internal/crc.h" #include "absl/crc/internal/crc32_x86_arm_combined_simd.h" #include "absl/crc/internal/crc_internal.h" #include "absl/memory/memory.h" #include "absl/numeric/bits.h" #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) #define ABSL_INTERNAL_CAN_USE_SIMD_CRC32C #endif namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { #if defined(ABSL_INTERNAL_CAN_USE_SIMD_CRC32C) // Implementation details not exported outside of file namespace { // Some machines have CRC acceleration hardware. // We can do a faster version of Extend() on such machines. class CRC32AcceleratedX86ARMCombined : public CRC32 { public: CRC32AcceleratedX86ARMCombined() {} ~CRC32AcceleratedX86ARMCombined() override {} void ExtendByZeroes(uint32_t* crc, size_t length) const override; uint32_t ComputeZeroConstant(size_t length) const; private: CRC32AcceleratedX86ARMCombined(const CRC32AcceleratedX86ARMCombined&) = delete; CRC32AcceleratedX86ARMCombined& operator=( const CRC32AcceleratedX86ARMCombined&) = delete; }; // Constants for switching between algorithms. // Chosen by comparing speed at different powers of 2. constexpr size_t kSmallCutoff = 256; constexpr size_t kMediumCutoff = 2048; #define ABSL_INTERNAL_STEP1(crc) \ do { \ crc = CRC32_u8(static_cast(crc), *p++); \ } while (0) #define ABSL_INTERNAL_STEP2(crc) \ do { \ crc = \ CRC32_u16(static_cast(crc), absl::little_endian::Load16(p)); \ p += 2; \ } while (0) #define ABSL_INTERNAL_STEP4(crc) \ do { \ crc = \ CRC32_u32(static_cast(crc), absl::little_endian::Load32(p)); \ p += 4; \ } while (0) #define ABSL_INTERNAL_STEP8(crc, data) \ do { \ crc = CRC32_u64(static_cast(crc), \ absl::little_endian::Load64(data)); \ data += 8; \ } while (0) #define ABSL_INTERNAL_STEP8BY2(crc0, crc1, p0, p1) \ do { \ ABSL_INTERNAL_STEP8(crc0, p0); \ ABSL_INTERNAL_STEP8(crc1, p1); \ } while (0) #define ABSL_INTERNAL_STEP8BY3(crc0, crc1, crc2, p0, p1, p2) \ do { \ ABSL_INTERNAL_STEP8(crc0, p0); \ ABSL_INTERNAL_STEP8(crc1, p1); \ ABSL_INTERNAL_STEP8(crc2, p2); \ } while (0) namespace { uint32_t multiply(uint32_t a, uint32_t b) { V128 shifts = V128_From2x64(0, 1); V128 power = V128_From2x64(0, a); V128 crc = V128_From2x64(0, b); V128 res = V128_PMulLow(power, crc); // Combine crc values res = V128_ShiftLeft64(res, shifts); return static_cast(V128_Extract32<1>(res)) ^ CRC32_u32(0, static_cast(V128_Low64(res))); } // Powers of crc32c polynomial, for faster ExtendByZeros. // Verified against folly: // folly/hash/detail/Crc32CombineDetail.cpp constexpr uint32_t kCRC32CPowers[] = { 0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955, 0xb8fdb1e7, 0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62, 0x28461564, 0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f, 0x538586e3, 0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe, 0xe94ca9bc, 0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0x82f63b78, 0x6ea2d55c, 0x18b8ea18, 0x510ac59a, 0xb82be955, 0xb8fdb1e7, 0x88e56f72, 0x74c360a4, 0xe4172b16, 0x0d65762a, 0x35d73a62, 0x28461564, 0xbf455269, 0xe2ea32dc, 0xfe7740e6, 0xf946610b, 0x3c204f8f, 0x538586e3, 0x59726915, 0x734d5309, 0xbc1ac763, 0x7d0722cc, 0xd289cabe, 0xe94ca9bc, 0x05b74f3f, 0xa51e1f42, 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, }; } // namespace // Compute a magic constant, so that multiplying by it is the same as // extending crc by length zeros. uint32_t CRC32AcceleratedX86ARMCombined::ComputeZeroConstant( size_t length) const { // Lowest 2 bits are handled separately in ExtendByZeroes length >>= 2; int index = absl::countr_zero(length); uint32_t prev = kCRC32CPowers[index]; length &= length - 1; while (length) { // For each bit of length, extend by 2**n zeros. index = absl::countr_zero(length); prev = multiply(prev, kCRC32CPowers[index]); length &= length - 1; } return prev; } void CRC32AcceleratedX86ARMCombined::ExtendByZeroes(uint32_t* crc, size_t length) const { uint32_t val = *crc; // Don't bother with multiplication for small length. switch (length & 3) { case 0: break; case 1: val = CRC32_u8(val, 0); break; case 2: val = CRC32_u16(val, 0); break; case 3: val = CRC32_u8(val, 0); val = CRC32_u16(val, 0); break; } if (length > 3) { val = multiply(val, ComputeZeroConstant(length)); } *crc = val; } // Taken from Intel paper "Fast CRC Computation for iSCSI Polynomial Using CRC32 // Instruction" // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf // We only need every 4th value, because we unroll loop by 4. constexpr uint64_t kClmulConstants[] = { 0x09e4addf8, 0x0ba4fc28e, 0x00d3b6092, 0x09e4addf8, 0x0ab7aff2a, 0x102f9b8a2, 0x0b9e02b86, 0x00d3b6092, 0x1bf2e8b8a, 0x18266e456, 0x0d270f1a2, 0x0ab7aff2a, 0x11eef4f8e, 0x083348832, 0x0dd7e3b0c, 0x0b9e02b86, 0x0271d9844, 0x1b331e26a, 0x06b749fb2, 0x1bf2e8b8a, 0x0e6fc4e6a, 0x0ce7f39f4, 0x0d7a4825c, 0x0d270f1a2, 0x026f6a60a, 0x12ed0daac, 0x068bce87a, 0x11eef4f8e, 0x1329d9f7e, 0x0b3e32c28, 0x0170076fa, 0x0dd7e3b0c, 0x1fae1cc66, 0x010746f3c, 0x086d8e4d2, 0x0271d9844, 0x0b3af077a, 0x093a5f730, 0x1d88abd4a, 0x06b749fb2, 0x0c9c8b782, 0x0cec3662e, 0x1ddffc5d4, 0x0e6fc4e6a, 0x168763fa6, 0x0b0cd4768, 0x19b1afbc4, 0x0d7a4825c, 0x123888b7a, 0x00167d312, 0x133d7a042, 0x026f6a60a, 0x000bcf5f6, 0x19d34af3a, 0x1af900c24, 0x068bce87a, 0x06d390dec, 0x16cba8aca, 0x1f16a3418, 0x1329d9f7e, 0x19fb2a8b0, 0x02178513a, 0x1a0f717c4, 0x0170076fa, }; enum class CutoffStrategy { // Use 3 CRC streams to fold into 1. Fold3, // Unroll CRC instructions for 64 bytes. Unroll64CRC, }; // Base class for CRC32AcceleratedX86ARMCombinedMultipleStreams containing the // methods and data that don't need the template arguments. class CRC32AcceleratedX86ARMCombinedMultipleStreamsBase : public CRC32AcceleratedX86ARMCombined { protected: // Update partialCRC with crc of 64 byte block. Calling FinalizePclmulStream // would produce a single crc checksum, but it is expensive. PCLMULQDQ has a // high latency, so we run 4 128-bit partial checksums that can be reduced to // a single value by FinalizePclmulStream later. Computing crc for arbitrary // polynomialas with PCLMULQDQ is described in Intel paper "Fast CRC // Computation for Generic Polynomials Using PCLMULQDQ Instruction" // https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf // We are applying it to CRC32C polynomial. ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul( const uint8_t* p, V128* partialCRC) const { V128 loopMultiplicands = V128_Load(reinterpret_cast(k1k2)); V128 partialCRC1 = partialCRC[0]; V128 partialCRC2 = partialCRC[1]; V128 partialCRC3 = partialCRC[2]; V128 partialCRC4 = partialCRC[3]; V128 tmp1 = V128_PMulHi(partialCRC1, loopMultiplicands); V128 tmp2 = V128_PMulHi(partialCRC2, loopMultiplicands); V128 tmp3 = V128_PMulHi(partialCRC3, loopMultiplicands); V128 tmp4 = V128_PMulHi(partialCRC4, loopMultiplicands); V128 data1 = V128_LoadU(reinterpret_cast(p + 16 * 0)); V128 data2 = V128_LoadU(reinterpret_cast(p + 16 * 1)); V128 data3 = V128_LoadU(reinterpret_cast(p + 16 * 2)); V128 data4 = V128_LoadU(reinterpret_cast(p + 16 * 3)); partialCRC1 = V128_PMulLow(partialCRC1, loopMultiplicands); partialCRC2 = V128_PMulLow(partialCRC2, loopMultiplicands); partialCRC3 = V128_PMulLow(partialCRC3, loopMultiplicands); partialCRC4 = V128_PMulLow(partialCRC4, loopMultiplicands); partialCRC1 = V128_Xor(tmp1, partialCRC1); partialCRC2 = V128_Xor(tmp2, partialCRC2); partialCRC3 = V128_Xor(tmp3, partialCRC3); partialCRC4 = V128_Xor(tmp4, partialCRC4); partialCRC1 = V128_Xor(partialCRC1, data1); partialCRC2 = V128_Xor(partialCRC2, data2); partialCRC3 = V128_Xor(partialCRC3, data3); partialCRC4 = V128_Xor(partialCRC4, data4); partialCRC[0] = partialCRC1; partialCRC[1] = partialCRC2; partialCRC[2] = partialCRC3; partialCRC[3] = partialCRC4; } // Reduce partialCRC produced by Process64BytesPclmul into a single value, // that represents crc checksum of all the processed bytes. ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t FinalizePclmulStream(V128* partialCRC) const { V128 partialCRC1 = partialCRC[0]; V128 partialCRC2 = partialCRC[1]; V128 partialCRC3 = partialCRC[2]; V128 partialCRC4 = partialCRC[3]; // Combine 4 vectors of partial crc into a single vector. V128 reductionMultiplicands = V128_Load(reinterpret_cast(k5k6)); V128 low = V128_PMulLow(reductionMultiplicands, partialCRC1); V128 high = V128_PMulHi(reductionMultiplicands, partialCRC1); partialCRC1 = V128_Xor(low, high); partialCRC1 = V128_Xor(partialCRC1, partialCRC2); low = V128_PMulLow(reductionMultiplicands, partialCRC3); high = V128_PMulHi(reductionMultiplicands, partialCRC3); partialCRC3 = V128_Xor(low, high); partialCRC3 = V128_Xor(partialCRC3, partialCRC4); reductionMultiplicands = V128_Load(reinterpret_cast(k3k4)); low = V128_PMulLow(reductionMultiplicands, partialCRC1); high = V128_PMulHi(reductionMultiplicands, partialCRC1); V128 fullCRC = V128_Xor(low, high); fullCRC = V128_Xor(fullCRC, partialCRC3); // Reduce fullCRC into scalar value. reductionMultiplicands = V128_Load(reinterpret_cast(k5k6)); V128 mask = V128_Load(reinterpret_cast(kMask)); V128 tmp = V128_PMul01(reductionMultiplicands, fullCRC); fullCRC = V128_ShiftRight<8>(fullCRC); fullCRC = V128_Xor(fullCRC, tmp); reductionMultiplicands = V128_Load(reinterpret_cast(k7k0)); tmp = V128_ShiftRight<4>(fullCRC); fullCRC = V128_And(fullCRC, mask); fullCRC = V128_PMulLow(reductionMultiplicands, fullCRC); fullCRC = V128_Xor(tmp, fullCRC); reductionMultiplicands = V128_Load(reinterpret_cast(kPoly)); tmp = V128_And(fullCRC, mask); tmp = V128_PMul01(reductionMultiplicands, tmp); tmp = V128_And(tmp, mask); tmp = V128_PMulLow(reductionMultiplicands, tmp); fullCRC = V128_Xor(tmp, fullCRC); return static_cast(V128_Extract32<1>(fullCRC)); } // Update crc with 64 bytes of data from p. ABSL_ATTRIBUTE_ALWAYS_INLINE uint64_t Process64BytesCRC(const uint8_t* p, uint64_t crc) const { for (int i = 0; i < 8; i++) { crc = CRC32_u64(static_cast(crc), absl::little_endian::Load64(p)); p += 8; } return crc; } // Generated by crc32c_x86_test --crc32c_generate_constants=true // and verified against constants in linux kernel for S390: // https://github.com/torvalds/linux/blob/master/arch/s390/crypto/crc32le-vx.S alignas(16) static constexpr uint64_t k1k2[2] = {0x0740eef02, 0x09e4addf8}; alignas(16) static constexpr uint64_t k3k4[2] = {0x1384aa63a, 0x0ba4fc28e}; alignas(16) static constexpr uint64_t k5k6[2] = {0x0f20c0dfe, 0x14cd00bd6}; alignas(16) static constexpr uint64_t k7k0[2] = {0x0dd45aab8, 0x000000000}; alignas(16) static constexpr uint64_t kPoly[2] = {0x105ec76f0, 0x0dea713f1}; alignas(16) static constexpr uint32_t kMask[4] = {~0u, 0u, ~0u, 0u}; // Medium runs of bytes are broken into groups of kGroupsSmall blocks of same // size. Each group is CRCed in parallel then combined at the end of the // block. static constexpr size_t kGroupsSmall = 3; // For large runs we use up to kMaxStreams blocks computed with CRC // instruction, and up to kMaxStreams blocks computed with PCLMULQDQ, which // are combined in the end. static constexpr size_t kMaxStreams = 3; }; #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL alignas(16) constexpr uint64_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k1k2[2]; alignas(16) constexpr uint64_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k3k4[2]; alignas(16) constexpr uint64_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k5k6[2]; alignas(16) constexpr uint64_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k7k0[2]; alignas(16) constexpr uint64_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kPoly[2]; alignas(16) constexpr uint32_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMask[4]; constexpr size_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kGroupsSmall; constexpr size_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMaxStreams; #endif // ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL template class CRC32AcceleratedX86ARMCombinedMultipleStreams : public CRC32AcceleratedX86ARMCombinedMultipleStreamsBase { ABSL_ATTRIBUTE_HOT void Extend(uint32_t* crc, const void* bytes, size_t length) const override { static_assert(num_crc_streams >= 1 && num_crc_streams <= kMaxStreams, "Invalid number of crc streams"); static_assert(num_pclmul_streams >= 0 && num_pclmul_streams <= kMaxStreams, "Invalid number of pclmul streams"); const uint8_t* p = static_cast(bytes); const uint8_t* e = p + length; uint32_t l = *crc; uint64_t l64; // We have dedicated instruction for 1,2,4 and 8 bytes. if (length & 8) { ABSL_INTERNAL_STEP8(l, p); length &= ~size_t{8}; } if (length & 4) { ABSL_INTERNAL_STEP4(l); length &= ~size_t{4}; } if (length & 2) { ABSL_INTERNAL_STEP2(l); length &= ~size_t{2}; } if (length & 1) { ABSL_INTERNAL_STEP1(l); length &= ~size_t{1}; } if (length == 0) { *crc = l; return; } // length is now multiple of 16. // For small blocks just run simple loop, because cost of combining multiple // streams is significant. if (strategy != CutoffStrategy::Unroll64CRC) { if (length < kSmallCutoff) { while (length >= 16) { ABSL_INTERNAL_STEP8(l, p); ABSL_INTERNAL_STEP8(l, p); length -= 16; } *crc = l; return; } } // For medium blocks we run 3 crc streams and combine them as described in // Intel paper above. Running 4th stream doesn't help, because crc // instruction has latency 3 and throughput 1. if (length < kMediumCutoff) { l64 = l; if (strategy == CutoffStrategy::Fold3) { uint64_t l641 = 0; uint64_t l642 = 0; const size_t blockSize = 32; size_t bs = static_cast(e - p) / kGroupsSmall / blockSize; const uint8_t* p1 = p + bs * blockSize; const uint8_t* p2 = p1 + bs * blockSize; for (size_t i = 0; i + 1 < bs; ++i) { ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); PrefetchToLocalCache( reinterpret_cast(p + kPrefetchHorizonMedium)); PrefetchToLocalCache( reinterpret_cast(p1 + kPrefetchHorizonMedium)); PrefetchToLocalCache( reinterpret_cast(p2 + kPrefetchHorizonMedium)); } // Don't run crc on last 8 bytes. ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY3(l64, l641, l642, p, p1, p2); ABSL_INTERNAL_STEP8BY2(l64, l641, p, p1); V128 magic = *(reinterpret_cast(kClmulConstants) + bs - 1); V128 tmp = V128_From2x64(0, l64); V128 res1 = V128_PMulLow(tmp, magic); tmp = V128_From2x64(0, l641); V128 res2 = V128_PMul10(tmp, magic); V128 x = V128_Xor(res1, res2); l64 = static_cast(V128_Low64(x)) ^ absl::little_endian::Load64(p2); l64 = CRC32_u64(static_cast(l642), l64); p = p2 + 8; } else if (strategy == CutoffStrategy::Unroll64CRC) { while ((e - p) >= 64) { l64 = Process64BytesCRC(p, l64); p += 64; } } } else { // There is a lot of data, we can ignore combine costs and run all // requested streams (num_crc_streams + num_pclmul_streams), // using prefetch. CRC and PCLMULQDQ use different cpu execution units, // so on some cpus it makes sense to execute both of them for different // streams. // Point x at first 8-byte aligned byte in string. const uint8_t* x = RoundUp<8>(p); // Process bytes until p is 8-byte aligned, if that isn't past the end. while (p != x) { ABSL_INTERNAL_STEP1(l); } size_t bs = static_cast(e - p) / (num_crc_streams + num_pclmul_streams) / 64; const uint8_t* crc_streams[kMaxStreams]; const uint8_t* pclmul_streams[kMaxStreams]; // We are guaranteed to have at least one crc stream. crc_streams[0] = p; for (size_t i = 1; i < num_crc_streams; i++) { crc_streams[i] = crc_streams[i - 1] + bs * 64; } pclmul_streams[0] = crc_streams[num_crc_streams - 1] + bs * 64; for (size_t i = 1; i < num_pclmul_streams; i++) { pclmul_streams[i] = pclmul_streams[i - 1] + bs * 64; } // Per stream crc sums. uint64_t l64_crc[kMaxStreams] = {l}; uint64_t l64_pclmul[kMaxStreams] = {0}; // Peel first iteration, because PCLMULQDQ stream, needs setup. for (size_t i = 0; i < num_crc_streams; i++) { l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]); crc_streams[i] += 16 * 4; } V128 partialCRC[kMaxStreams][4]; for (size_t i = 0; i < num_pclmul_streams; i++) { partialCRC[i][0] = V128_LoadU( reinterpret_cast(pclmul_streams[i] + 16 * 0)); partialCRC[i][1] = V128_LoadU( reinterpret_cast(pclmul_streams[i] + 16 * 1)); partialCRC[i][2] = V128_LoadU( reinterpret_cast(pclmul_streams[i] + 16 * 2)); partialCRC[i][3] = V128_LoadU( reinterpret_cast(pclmul_streams[i] + 16 * 3)); pclmul_streams[i] += 16 * 4; } for (size_t i = 1; i < bs; i++) { // Prefetch data for next iterations. for (size_t j = 0; j < num_crc_streams; j++) { PrefetchToLocalCache( reinterpret_cast(crc_streams[j] + kPrefetchHorizon)); } for (size_t j = 0; j < num_pclmul_streams; j++) { PrefetchToLocalCache(reinterpret_cast(pclmul_streams[j] + kPrefetchHorizon)); } // We process each stream in 64 byte blocks. This can be written as // for (int i = 0; i < num_pclmul_streams; i++) { // Process64BytesPclmul(pclmul_streams[i], partialCRC[i]); // pclmul_streams[i] += 16 * 4; // } // for (int i = 0; i < num_crc_streams; i++) { // l64_crc[i] = Process64BytesCRC(crc_streams[i], l64_crc[i]); // crc_streams[i] += 16*4; // } // But unrolling and interleaving PCLMULQDQ and CRC blocks manually // gives ~2% performance boost. l64_crc[0] = Process64BytesCRC(crc_streams[0], l64_crc[0]); crc_streams[0] += 16 * 4; if (num_pclmul_streams > 0) { Process64BytesPclmul(pclmul_streams[0], partialCRC[0]); pclmul_streams[0] += 16 * 4; } if (num_crc_streams > 1) { l64_crc[1] = Process64BytesCRC(crc_streams[1], l64_crc[1]); crc_streams[1] += 16 * 4; } if (num_pclmul_streams > 1) { Process64BytesPclmul(pclmul_streams[1], partialCRC[1]); pclmul_streams[1] += 16 * 4; } if (num_crc_streams > 2) { l64_crc[2] = Process64BytesCRC(crc_streams[2], l64_crc[2]); crc_streams[2] += 16 * 4; } if (num_pclmul_streams > 2) { Process64BytesPclmul(pclmul_streams[2], partialCRC[2]); pclmul_streams[2] += 16 * 4; } } // PCLMULQDQ based streams require special final step; // CRC based don't. for (size_t i = 0; i < num_pclmul_streams; i++) { l64_pclmul[i] = FinalizePclmulStream(partialCRC[i]); } // Combine all streams into single result. uint32_t magic = ComputeZeroConstant(bs * 64); l64 = l64_crc[0]; for (size_t i = 1; i < num_crc_streams; i++) { l64 = multiply(static_cast(l64), magic); l64 ^= l64_crc[i]; } for (size_t i = 0; i < num_pclmul_streams; i++) { l64 = multiply(static_cast(l64), magic); l64 ^= l64_pclmul[i]; } // Update p. if (num_pclmul_streams > 0) { p = pclmul_streams[num_pclmul_streams - 1]; } else { p = crc_streams[num_crc_streams - 1]; } } l = static_cast(l64); while ((e - p) >= 16) { ABSL_INTERNAL_STEP8(l, p); ABSL_INTERNAL_STEP8(l, p); } // Process the last few bytes while (p != e) { ABSL_INTERNAL_STEP1(l); } #undef ABSL_INTERNAL_STEP8BY3 #undef ABSL_INTERNAL_STEP8BY2 #undef ABSL_INTERNAL_STEP8 #undef ABSL_INTERNAL_STEP4 #undef ABSL_INTERNAL_STEP2 #undef ABSL_INTERNAL_STEP1 *crc = l; } }; } // namespace // Intel processors with SSE4.2 have an instruction for one particular // 32-bit CRC polynomial: crc32c CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { CpuType type = GetCpuType(); switch (type) { case CpuType::kIntelHaswell: case CpuType::kAmdRome: case CpuType::kAmdNaples: case CpuType::kAmdMilan: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 1, CutoffStrategy::Fold3>(); // PCLMULQDQ is fast, use combined PCLMULQDQ + CRC implementation. case CpuType::kIntelCascadelakeXeon: case CpuType::kIntelSkylakeXeon: case CpuType::kIntelBroadwell: case CpuType::kIntelSkylake: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 2, CutoffStrategy::Fold3>(); // PCLMULQDQ is slow, don't use it. case CpuType::kIntelIvybridge: case CpuType::kIntelSandybridge: case CpuType::kIntelWestmere: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 0, CutoffStrategy::Fold3>(); case CpuType::kArmNeoverseN1: return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 1, CutoffStrategy::Unroll64CRC>(); #if defined(__aarch64__) default: // Not all ARM processors support the needed instructions, so check here // before trying to use an accelerated implementation. if (SupportsArmCRC32PMULL()) { return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 1, 1, CutoffStrategy::Unroll64CRC>(); } else { return nullptr; } #else default: // Something else, play it safe and assume slow PCLMULQDQ. return new CRC32AcceleratedX86ARMCombinedMultipleStreams< 3, 0, CutoffStrategy::Fold3>(); #endif } } std::vector> NewCRC32AcceleratedX86ARMCombinedAll() { auto ret = std::vector>(); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); ret.push_back(absl::make_unique>()); return ret; } #else // !ABSL_INTERNAL_CAN_USE_SIMD_CRC32C std::vector> NewCRC32AcceleratedX86ARMCombinedAll() { return std::vector>(); } // no hardware acceleration available CRCImpl* TryNewCRC32AcceleratedX86ARMCombined() { return nullptr; } #endif } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/crc32c.h0000644000175000017510000000235714737212474022163 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC32C_H_ #define ABSL_CRC_INTERNAL_CRC32C_H_ #include "absl/base/config.h" #include "absl/crc/crc32c.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // Modifies a CRC32 value by removing `length` bytes with a value of 0 from // the end of the string. // // This is the inverse operation of ExtendCrc32cByZeroes(). // // This operation has a runtime cost of O(log(`length`)) // // Internal implementation detail, exposed for testing only. crc32c_t UnextendCrc32cByZeroes(crc32c_t initial_crc, size_t length); } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC32C_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/cpu_detect.cc0000644000175000017510000001700614737212474023356 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/crc/internal/cpu_detect.h" #include #include #include "absl/base/config.h" #if defined(__aarch64__) && defined(__linux__) #include #include #endif #if defined(_WIN32) || defined(_WIN64) #include #endif #if defined(__x86_64__) || defined(_M_X64) #if ABSL_HAVE_BUILTIN(__cpuid) // MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers // for non-Windows build environments. extern void __cpuid(int[4], int); #elif !defined(_WIN32) && !defined(_WIN64) // MSVC defines this function for us. // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex static void __cpuid(int cpu_info[4], int info_type) { __asm__ volatile("cpuid \n\t" : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) : "a"(info_type), "c"(0)); } #endif // !defined(_WIN32) && !defined(_WIN64) #endif // defined(__x86_64__) || defined(_M_X64) namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { #if defined(__x86_64__) || defined(_M_X64) namespace { enum class Vendor { kUnknown, kIntel, kAmd, }; Vendor GetVendor() { // Get the vendor string (issue CPUID with eax = 0). int cpu_info[4]; __cpuid(cpu_info, 0); std::string vendor; vendor.append(reinterpret_cast(&cpu_info[1]), 4); vendor.append(reinterpret_cast(&cpu_info[3]), 4); vendor.append(reinterpret_cast(&cpu_info[2]), 4); if (vendor == "GenuineIntel") { return Vendor::kIntel; } else if (vendor == "AuthenticAMD") { return Vendor::kAmd; } else { return Vendor::kUnknown; } } CpuType GetIntelCpuType() { // To get general information and extended features we send eax = 1 and // ecx = 0 to cpuid. The response is returned in eax, ebx, ecx and edx. // (See Intel 64 and IA-32 Architectures Software Developer's Manual // Volume 2A: Instruction Set Reference, A-M CPUID). // https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex int cpu_info[4]; __cpuid(cpu_info, 1); // Response in eax bits as follows: // 0-3 (stepping id) // 4-7 (model number), // 8-11 (family code), // 12-13 (processor type), // 16-19 (extended model) // 20-27 (extended family) int family = (cpu_info[0] >> 8) & 0x0f; int model_num = (cpu_info[0] >> 4) & 0x0f; int ext_family = (cpu_info[0] >> 20) & 0xff; int ext_model_num = (cpu_info[0] >> 16) & 0x0f; int brand_id = cpu_info[1] & 0xff; // Process the extended family and model info if necessary if (family == 0x0f) { family += ext_family; } if (family == 0x0f || family == 0x6) { model_num += (ext_model_num << 4); } switch (brand_id) { case 0: // no brand ID, so parse CPU family/model switch (family) { case 6: // Most PentiumIII processors are in this category switch (model_num) { case 0x2c: // Westmere: Gulftown return CpuType::kIntelWestmere; case 0x2d: // Sandybridge return CpuType::kIntelSandybridge; case 0x3e: // Ivybridge return CpuType::kIntelIvybridge; case 0x3c: // Haswell (client) case 0x3f: // Haswell return CpuType::kIntelHaswell; case 0x4f: // Broadwell case 0x56: // BroadwellDE return CpuType::kIntelBroadwell; case 0x55: // Skylake Xeon if ((cpu_info[0] & 0x0f) < 5) { // stepping < 5 is skylake return CpuType::kIntelSkylakeXeon; } else { // stepping >= 5 is cascadelake return CpuType::kIntelCascadelakeXeon; } case 0x5e: // Skylake (client) return CpuType::kIntelSkylake; default: return CpuType::kUnknown; } default: return CpuType::kUnknown; } default: return CpuType::kUnknown; } } CpuType GetAmdCpuType() { // To get general information and extended features we send eax = 1 and // ecx = 0 to cpuid. The response is returned in eax, ebx, ecx and edx. // (See Intel 64 and IA-32 Architectures Software Developer's Manual // Volume 2A: Instruction Set Reference, A-M CPUID). // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex int cpu_info[4]; __cpuid(cpu_info, 1); // Response in eax bits as follows: // 0-3 (stepping id) // 4-7 (model number), // 8-11 (family code), // 12-13 (processor type), // 16-19 (extended model) // 20-27 (extended family) int family = (cpu_info[0] >> 8) & 0x0f; int model_num = (cpu_info[0] >> 4) & 0x0f; int ext_family = (cpu_info[0] >> 20) & 0xff; int ext_model_num = (cpu_info[0] >> 16) & 0x0f; if (family == 0x0f) { family += ext_family; model_num += (ext_model_num << 4); } switch (family) { case 0x17: switch (model_num) { case 0x0: // Stepping Ax case 0x1: // Stepping Bx return CpuType::kAmdNaples; case 0x30: // Stepping Ax case 0x31: // Stepping Bx return CpuType::kAmdRome; default: return CpuType::kUnknown; } break; case 0x19: switch (model_num) { case 0x1: // Stepping B0 return CpuType::kAmdMilan; default: return CpuType::kUnknown; } break; default: return CpuType::kUnknown; } } } // namespace CpuType GetCpuType() { switch (GetVendor()) { case Vendor::kIntel: return GetIntelCpuType(); case Vendor::kAmd: return GetAmdCpuType(); default: return CpuType::kUnknown; } } bool SupportsArmCRC32PMULL() { return false; } #elif defined(__aarch64__) && defined(__linux__) #ifndef HWCAP_CPUID #define HWCAP_CPUID (1 << 11) #endif #define ABSL_INTERNAL_AARCH64_ID_REG_READ(id, val) \ asm("mrs %0, " #id : "=r"(val)) CpuType GetCpuType() { // MIDR_EL1 is not visible to EL0, however the access will be emulated by // linux if AT_HWCAP has HWCAP_CPUID set. // // This method will be unreliable on heterogeneous computing systems (ex: // big.LITTLE) since the value of MIDR_EL1 will change based on the calling // thread. uint64_t hwcaps = getauxval(AT_HWCAP); if (hwcaps & HWCAP_CPUID) { uint64_t midr = 0; ABSL_INTERNAL_AARCH64_ID_REG_READ(MIDR_EL1, midr); uint32_t implementer = (midr >> 24) & 0xff; uint32_t part_number = (midr >> 4) & 0xfff; if (implementer == 0x41 && part_number == 0xd0c) { return CpuType::kArmNeoverseN1; } } return CpuType::kUnknown; } bool SupportsArmCRC32PMULL() { uint64_t hwcaps = getauxval(AT_HWCAP); return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL); } #else CpuType GetCpuType() { return CpuType::kUnknown; } bool SupportsArmCRC32PMULL() { return false; } #endif } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/non_temporal_arm_intrinsics.h0000644000175000017510000000626714737212474026711 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_ #define ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_ #include "absl/base/config.h" #ifdef __aarch64__ #include typedef int64x2_t __m128i; /* 128-bit vector containing integers */ #define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x) #define vreinterpretq_s64_m128i(x) (x) // Guarantees that every preceding store is globally visible before any // subsequent store. // https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx static inline __attribute__((always_inline)) void _mm_sfence(void) { __sync_synchronize(); } // Load 128-bits of integer data from unaligned memory into dst. This intrinsic // may perform better than _mm_loadu_si128 when the data crosses a cache line // boundary. // // dst[127:0] := MEM[mem_addr+127:mem_addr] // // https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 #define _mm_lddqu_si128 _mm_loadu_si128 // Loads 128-bit value. : // https://msdn.microsoft.com/zh-cn/library/f4k12ae8(v=vs.90).aspx static inline __attribute__((always_inline)) __m128i _mm_loadu_si128( const __m128i *p) { return vreinterpretq_m128i_s32(vld1q_s32((const int32_t *)p)); } // Stores the data in a to the address p without polluting the caches. If the // cache line containing address p is already in the cache, the cache will be // updated. // https://msdn.microsoft.com/en-us/library/ba08y07y%28v=vs.90%29.aspx static inline __attribute__((always_inline)) void _mm_stream_si128(__m128i *p, __m128i a) { #if ABSL_HAVE_BUILTIN(__builtin_nontemporal_store) __builtin_nontemporal_store(a, p); #else vst1q_s64((int64_t *)p, vreinterpretq_s64_m128i(a)); #endif } // Sets the 16 signed 8-bit integer values. // https://msdn.microsoft.com/en-us/library/x0cx8zd3(v=vs.90).aspx static inline __attribute__((always_inline)) __m128i _mm_set_epi8( signed char b15, signed char b14, signed char b13, signed char b12, signed char b11, signed char b10, signed char b9, signed char b8, signed char b7, signed char b6, signed char b5, signed char b4, signed char b3, signed char b2, signed char b1, signed char b0) { int8_t __attribute__((aligned(16))) data[16] = {(int8_t)b0, (int8_t)b1, (int8_t)b2, (int8_t)b3, (int8_t)b4, (int8_t)b5, (int8_t)b6, (int8_t)b7, (int8_t)b8, (int8_t)b9, (int8_t)b10, (int8_t)b11, (int8_t)b12, (int8_t)b13, (int8_t)b14, (int8_t)b15}; return (__m128i)vld1q_s8(data); } #endif // __aarch64__ #endif // ABSL_CRC_INTERNAL_NON_TEMPORAL_ARM_INTRINSICS_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc32c_inline.h0000644000175000017510000000407414737212474023517 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ #define ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ #include #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/crc/internal/crc32_x86_arm_combined_simd.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // CRC32C implementation optimized for small inputs. // Either computes crc and return true, or if there is // no hardware support does nothing and returns false. inline bool ExtendCrc32cInline(uint32_t* crc, const char* p, size_t n) { #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) constexpr uint32_t kCrc32Xor = 0xffffffffU; *crc ^= kCrc32Xor; if (n & 1) { *crc = CRC32_u8(*crc, static_cast(*p)); n--; p++; } if (n & 2) { *crc = CRC32_u16(*crc, absl::little_endian::Load16(p)); n -= 2; p += 2; } if (n & 4) { *crc = CRC32_u32(*crc, absl::little_endian::Load32(p)); n -= 4; p += 4; } while (n) { *crc = CRC32_u64(*crc, absl::little_endian::Load64(p)); n -= 8; p += 8; } *crc ^= kCrc32Xor; return true; #else // No hardware support, signal the need to fallback. static_cast(crc); static_cast(p); static_cast(n); return false; #endif // defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || // defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC32C_INLINE_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_memcpy_x86_64.cc0000644000175000017510000004157314737212474024404 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Simultaneous memcopy and CRC-32C for x86-64. Uses integer registers because // XMM registers do not support the CRC instruction (yet). While copying, // compute the running CRC of the data being copied. // // It is assumed that any CPU running this code has SSE4.2 instructions // available (for CRC32C). This file will do nothing if that is not true. // // The CRC instruction has a 3-byte latency, and we are stressing the ALU ports // here (unlike a traditional memcopy, which has almost no ALU use), so we will // need to copy in such a way that the CRC unit is used efficiently. We have two // regimes in this code: // 1. For operations of size < kCrcSmallSize, do the CRC then the memcpy // 2. For operations of size > kCrcSmallSize: // a) compute an initial CRC + copy on a small amount of data to align the // destination pointer on a 16-byte boundary. // b) Split the data into 3 main regions and a tail (smaller than 48 bytes) // c) Do the copy and CRC of the 3 main regions, interleaving (start with // full cache line copies for each region, then move to single 16 byte // pieces per region). // d) Combine the CRCs with CRC32C::Concat. // e) Copy the tail and extend the CRC with the CRC of the tail. // This method is not ideal for op sizes between ~1k and ~8k because CRC::Concat // takes a significant amount of time. A medium-sized approach could be added // using 3 CRCs over fixed-size blocks where the zero-extensions required for // CRC32C::Concat can be precomputed. #ifdef __SSE4_2__ #include #endif #ifdef _MSC_VER #include #endif #include #include #include #include #include "absl/base/dynamic_annotations.h" #include "absl/base/optimization.h" #include "absl/base/prefetch.h" #include "absl/crc/crc32c.h" #include "absl/crc/internal/cpu_detect.h" #include "absl/crc/internal/crc_memcpy.h" #include "absl/strings/string_view.h" #ifdef ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { namespace { inline crc32c_t ShortCrcCopy(char* dst, const char* src, std::size_t length, crc32c_t crc) { // Small copy: just go 1 byte at a time: being nice to the branch predictor // is more important here than anything else uint32_t crc_uint32 = static_cast(crc); for (std::size_t i = 0; i < length; i++) { uint8_t data = *reinterpret_cast(src); crc_uint32 = _mm_crc32_u8(crc_uint32, data); *reinterpret_cast(dst) = data; ++src; ++dst; } return crc32c_t{crc_uint32}; } constexpr size_t kIntLoadsPerVec = sizeof(__m128i) / sizeof(uint64_t); // Common function for copying the tails of multiple large regions. template inline void LargeTailCopy(crc32c_t* crcs, char** dst, const char** src, size_t region_size, size_t copy_rounds) { std::array<__m128i, vec_regions> data; std::array int_data; while (copy_rounds > 0) { for (size_t i = 0; i < vec_regions; i++) { size_t region = i; auto* vsrc = reinterpret_cast(*src + region_size * region); auto* vdst = reinterpret_cast<__m128i*>(*dst + region_size * region); // Load the blocks, unaligned data[i] = _mm_loadu_si128(vsrc); // Store the blocks, aligned _mm_store_si128(vdst, data[i]); // Compute the running CRC crcs[region] = crc32c_t{static_cast( _mm_crc32_u64(static_cast(crcs[region]), static_cast(_mm_extract_epi64(data[i], 0))))}; crcs[region] = crc32c_t{static_cast( _mm_crc32_u64(static_cast(crcs[region]), static_cast(_mm_extract_epi64(data[i], 1))))}; } for (size_t i = 0; i < int_regions; i++) { size_t region = vec_regions + i; auto* usrc = reinterpret_cast(*src + region_size * region); auto* udst = reinterpret_cast(*dst + region_size * region); for (size_t j = 0; j < kIntLoadsPerVec; j++) { size_t data_index = i * kIntLoadsPerVec + j; int_data[data_index] = *(usrc + j); crcs[region] = crc32c_t{static_cast(_mm_crc32_u64( static_cast(crcs[region]), int_data[data_index]))}; *(udst + j) = int_data[data_index]; } } // Increment pointers *src += sizeof(__m128i); *dst += sizeof(__m128i); --copy_rounds; } } } // namespace template class AcceleratedCrcMemcpyEngine : public CrcMemcpyEngine { public: AcceleratedCrcMemcpyEngine() = default; AcceleratedCrcMemcpyEngine(const AcceleratedCrcMemcpyEngine&) = delete; AcceleratedCrcMemcpyEngine operator=(const AcceleratedCrcMemcpyEngine&) = delete; crc32c_t Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const override; }; template crc32c_t AcceleratedCrcMemcpyEngine::Compute( void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const { constexpr std::size_t kRegions = vec_regions + int_regions; constexpr uint32_t kCrcDataXor = uint32_t{0xffffffff}; constexpr std::size_t kBlockSize = sizeof(__m128i); constexpr std::size_t kCopyRoundSize = kRegions * kBlockSize; // Number of blocks per cacheline. constexpr std::size_t kBlocksPerCacheLine = ABSL_CACHELINE_SIZE / kBlockSize; char* dst_bytes = static_cast(dst); const char* src_bytes = static_cast(src); // Make sure that one prefetch per big block is enough to cover the whole // dataset, and we don't prefetch too much. static_assert(ABSL_CACHELINE_SIZE % kBlockSize == 0, "Cache lines are not divided evenly into blocks, may have " "unintended behavior!"); // Experimentally-determined boundary between a small and large copy. // Below this number, spin-up and concatenation of CRCs takes enough time that // it kills the throughput gains of using 3 regions and wide vectors. constexpr size_t kCrcSmallSize = 256; // Experimentally-determined prefetch distance. Main loop copies will // prefeth data 2 cache lines ahead. constexpr std::size_t kPrefetchAhead = 2 * ABSL_CACHELINE_SIZE; // Small-size CRC-memcpy : just do CRC + memcpy if (length < kCrcSmallSize) { crc32c_t crc = ExtendCrc32c(initial_crc, absl::string_view(src_bytes, length)); memcpy(dst, src, length); return crc; } // Start work on the CRC: undo the XOR from the previous calculation or set up // the initial value of the CRC. // initial_crc ^= kCrcDataXor; initial_crc = crc32c_t{static_cast(initial_crc) ^ kCrcDataXor}; // Do an initial alignment copy, so we can use aligned store instructions to // the destination pointer. We align the destination pointer because the // penalty for an unaligned load is small compared to the penalty of an // unaligned store on modern CPUs. std::size_t bytes_from_last_aligned = reinterpret_cast(dst) & (kBlockSize - 1); if (bytes_from_last_aligned != 0) { std::size_t bytes_for_alignment = kBlockSize - bytes_from_last_aligned; // Do the short-sized copy and CRC. initial_crc = ShortCrcCopy(dst_bytes, src_bytes, bytes_for_alignment, initial_crc); src_bytes += bytes_for_alignment; dst_bytes += bytes_for_alignment; length -= bytes_for_alignment; } // We are going to do the copy and CRC in kRegions regions to make sure that // we can saturate the CRC unit. The CRCs will be combined at the end of the // run. Copying will use the SSE registers, and we will extract words from // the SSE registers to add to the CRC. Initially, we run the loop one full // cache line per region at a time, in order to insert prefetches. // Initialize CRCs for kRegions regions. crc32c_t crcs[kRegions]; crcs[0] = initial_crc; for (size_t i = 1; i < kRegions; i++) { crcs[i] = crc32c_t{kCrcDataXor}; } // Find the number of rounds to copy and the region size. Also compute the // tail size here. size_t copy_rounds = length / kCopyRoundSize; // Find the size of each region and the size of the tail. const std::size_t region_size = copy_rounds * kBlockSize; const std::size_t tail_size = length - (kRegions * region_size); // Holding registers for data in each region. std::array<__m128i, vec_regions> vec_data; std::array int_data; // Main loop. while (copy_rounds > kBlocksPerCacheLine) { // Prefetch kPrefetchAhead bytes ahead of each pointer. for (size_t i = 0; i < kRegions; i++) { absl::PrefetchToLocalCache(src_bytes + kPrefetchAhead + region_size * i); absl::PrefetchToLocalCache(dst_bytes + kPrefetchAhead + region_size * i); } // Load and store data, computing CRC on the way. for (size_t i = 0; i < kBlocksPerCacheLine; i++) { // Copy and CRC the data for the CRC regions. for (size_t j = 0; j < vec_regions; j++) { // Cycle which regions get vector load/store and integer load/store, to // engage prefetching logic around vector load/stores and save issue // slots by using the integer registers. size_t region = (j + i) % kRegions; auto* vsrc = reinterpret_cast(src_bytes + region_size * region); auto* vdst = reinterpret_cast<__m128i*>(dst_bytes + region_size * region); // Load and CRC data. vec_data[j] = _mm_loadu_si128(vsrc + i); crcs[region] = crc32c_t{static_cast(_mm_crc32_u64( static_cast(crcs[region]), static_cast(_mm_extract_epi64(vec_data[j], 0))))}; crcs[region] = crc32c_t{static_cast(_mm_crc32_u64( static_cast(crcs[region]), static_cast(_mm_extract_epi64(vec_data[j], 1))))}; // Store the data. _mm_store_si128(vdst + i, vec_data[j]); } // Preload the partial CRCs for the CLMUL subregions. for (size_t j = 0; j < int_regions; j++) { // Cycle which regions get vector load/store and integer load/store, to // engage prefetching logic around vector load/stores and save issue // slots by using the integer registers. size_t region = (j + vec_regions + i) % kRegions; auto* usrc = reinterpret_cast(src_bytes + region_size * region); auto* udst = reinterpret_cast(dst_bytes + region_size * region); for (size_t k = 0; k < kIntLoadsPerVec; k++) { size_t data_index = j * kIntLoadsPerVec + k; // Load and CRC the data. int_data[data_index] = *(usrc + i * kIntLoadsPerVec + k); crcs[region] = crc32c_t{static_cast(_mm_crc32_u64( static_cast(crcs[region]), int_data[data_index]))}; // Store the data. *(udst + i * kIntLoadsPerVec + k) = int_data[data_index]; } } } // Increment pointers src_bytes += kBlockSize * kBlocksPerCacheLine; dst_bytes += kBlockSize * kBlocksPerCacheLine; copy_rounds -= kBlocksPerCacheLine; } // Copy and CRC the tails of each region. LargeTailCopy(crcs, &dst_bytes, &src_bytes, region_size, copy_rounds); // Move the source and destination pointers to the end of the region src_bytes += region_size * (kRegions - 1); dst_bytes += region_size * (kRegions - 1); // Finalize the first CRCs: XOR the internal CRCs by the XOR mask to undo the // XOR done before doing block copy + CRCs. for (size_t i = 0; i + 1 < kRegions; i++) { crcs[i] = crc32c_t{static_cast(crcs[i]) ^ kCrcDataXor}; } // Build a CRC of the first kRegions - 1 regions. crc32c_t full_crc = crcs[0]; for (size_t i = 1; i + 1 < kRegions; i++) { full_crc = ConcatCrc32c(full_crc, crcs[i], region_size); } // Copy and CRC the tail through the XMM registers. std::size_t tail_blocks = tail_size / kBlockSize; LargeTailCopy<0, 1>(&crcs[kRegions - 1], &dst_bytes, &src_bytes, 0, tail_blocks); // Final tail copy for under 16 bytes. crcs[kRegions - 1] = ShortCrcCopy(dst_bytes, src_bytes, tail_size - tail_blocks * kBlockSize, crcs[kRegions - 1]); // Finalize and concatenate the final CRC, then return. crcs[kRegions - 1] = crc32c_t{static_cast(crcs[kRegions - 1]) ^ kCrcDataXor}; return ConcatCrc32c(full_crc, crcs[kRegions - 1], region_size + tail_size); } CrcMemcpy::ArchSpecificEngines CrcMemcpy::GetArchSpecificEngines() { #ifdef UNDEFINED_BEHAVIOR_SANITIZER // UBSAN does not play nicely with unaligned loads (which we use a lot). // Get the underlying architecture. CpuType cpu_type = GetCpuType(); switch (cpu_type) { case CpuType::kUnknown: case CpuType::kAmdRome: case CpuType::kAmdNaples: case CpuType::kIntelCascadelakeXeon: case CpuType::kIntelSkylakeXeon: case CpuType::kIntelSkylake: case CpuType::kIntelBroadwell: case CpuType::kIntelHaswell: case CpuType::kIntelIvybridge: return { /*.temporal=*/new FallbackCrcMemcpyEngine(), /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(), }; // INTEL_SANDYBRIDGE performs better with SSE than AVX. case CpuType::kIntelSandybridge: return { /*.temporal=*/new FallbackCrcMemcpyEngine(), /*.non_temporal=*/new CrcNonTemporalMemcpyEngine(), }; default: return {/*.temporal=*/new FallbackCrcMemcpyEngine(), /*.non_temporal=*/new FallbackCrcMemcpyEngine()}; } #else // Get the underlying architecture. CpuType cpu_type = GetCpuType(); switch (cpu_type) { // On Zen 2, PEXTRQ uses 2 micro-ops, including one on the vector store port // which data movement from the vector registers to the integer registers // (where CRC32C happens) to crowd the same units as vector stores. As a // result, using that path exclusively causes bottlenecking on this port. // We can avoid this bottleneck by using the integer side of the CPU for // most operations rather than the vector side. We keep a vector region to // engage some of the prefetching logic in the cache hierarchy which seems // to give vector instructions special treatment. These prefetch units see // strided access to each region, and do the right thing. case CpuType::kAmdRome: case CpuType::kAmdNaples: return { /*.temporal=*/new AcceleratedCrcMemcpyEngine<1, 2>(), /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(), }; // PCLMULQDQ is slow and we don't have wide enough issue width to take // advantage of it. For an unknown architecture, don't risk using CLMULs. case CpuType::kIntelCascadelakeXeon: case CpuType::kIntelSkylakeXeon: case CpuType::kIntelSkylake: case CpuType::kIntelBroadwell: case CpuType::kIntelHaswell: case CpuType::kIntelIvybridge: return { /*.temporal=*/new AcceleratedCrcMemcpyEngine<3, 0>(), /*.non_temporal=*/new CrcNonTemporalMemcpyAVXEngine(), }; // INTEL_SANDYBRIDGE performs better with SSE than AVX. case CpuType::kIntelSandybridge: return { /*.temporal=*/new AcceleratedCrcMemcpyEngine<3, 0>(), /*.non_temporal=*/new CrcNonTemporalMemcpyEngine(), }; default: return {/*.temporal=*/new FallbackCrcMemcpyEngine(), /*.non_temporal=*/new FallbackCrcMemcpyEngine()}; } #endif // UNDEFINED_BEHAVIOR_SANITIZER } // For testing, allow the user to specify which engine they want. std::unique_ptr CrcMemcpy::GetTestEngine(int vector, int integer) { if (vector == 3 && integer == 0) { return std::make_unique>(); } else if (vector == 1 && integer == 2) { return std::make_unique>(); } return nullptr; } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE s2/tools/vendor/abseil-cpp/absl/crc/internal/cpu_detect.h0000644000175000017510000000333614737212474023221 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CPU_DETECT_H_ #define ABSL_CRC_INTERNAL_CPU_DETECT_H_ #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // Enumeration of architectures that we have special-case tuning parameters for. // This set may change over time. enum class CpuType { kUnknown, kIntelHaswell, kAmdRome, kAmdNaples, kAmdMilan, kIntelCascadelakeXeon, kIntelSkylakeXeon, kIntelBroadwell, kIntelSkylake, kIntelIvybridge, kIntelSandybridge, kIntelWestmere, kArmNeoverseN1, }; // Returns the type of host CPU this code is running on. Returns kUnknown if // the host CPU is of unknown type, or if detection otherwise fails. CpuType GetCpuType(); // Returns whether the host CPU supports the CPU features needed for our // accelerated implementations. The CpuTypes enumerated above apart from // kUnknown support the required features. On unknown CPUs, we can use // this to see if it's safe to use hardware acceleration, though without any // tuning. bool SupportsArmCRC32PMULL(); } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CPU_DETECT_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_memcpy_fallback.cc0000644000175000017510000000521714737212474025200 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "absl/base/config.h" #include "absl/crc/crc32c.h" #include "absl/crc/internal/crc_memcpy.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { absl::crc32c_t FallbackCrcMemcpyEngine::Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const { constexpr size_t kBlockSize = 8192; absl::crc32c_t crc = initial_crc; const char* src_bytes = reinterpret_cast(src); char* dst_bytes = reinterpret_cast(dst); // Copy + CRC loop - run 8k chunks until we are out of full chunks. CRC // then copy was found to be slightly more efficient in our test cases. std::size_t offset = 0; for (; offset + kBlockSize < length; offset += kBlockSize) { crc = absl::ExtendCrc32c(crc, absl::string_view(src_bytes + offset, kBlockSize)); memcpy(dst_bytes + offset, src_bytes + offset, kBlockSize); } // Save some work if length is 0. if (offset < length) { std::size_t final_copy_size = length - offset; crc = absl::ExtendCrc32c( crc, absl::string_view(src_bytes + offset, final_copy_size)); memcpy(dst_bytes + offset, src_bytes + offset, final_copy_size); } return crc; } // Compile the following only if we don't have #ifndef ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE CrcMemcpy::ArchSpecificEngines CrcMemcpy::GetArchSpecificEngines() { CrcMemcpy::ArchSpecificEngines engines; engines.temporal = new FallbackCrcMemcpyEngine(); engines.non_temporal = new FallbackCrcMemcpyEngine(); return engines; } std::unique_ptr CrcMemcpy::GetTestEngine(int /*vector*/, int /*integer*/) { return std::make_unique(); } #endif // ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_memcpy.h0000644000175000017510000001031214737212474023213 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC_MEMCPY_H_ #define ABSL_CRC_INTERNAL_CRC_MEMCPY_H_ #include #include #include "absl/base/config.h" #include "absl/crc/crc32c.h" // Defined if the class AcceleratedCrcMemcpyEngine exists. #if defined(__x86_64__) && defined(__SSE4_2__) #define ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE 1 #elif defined(_MSC_VER) && defined(__AVX__) #define ABSL_INTERNAL_HAVE_X86_64_ACCELERATED_CRC_MEMCPY_ENGINE 1 #endif namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { class CrcMemcpyEngine { public: virtual ~CrcMemcpyEngine() = default; virtual crc32c_t Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const = 0; protected: CrcMemcpyEngine() = default; }; class CrcMemcpy { public: static crc32c_t CrcAndCopy(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc = crc32c_t{0}, bool non_temporal = false) { static const ArchSpecificEngines engines = GetArchSpecificEngines(); auto* engine = non_temporal ? engines.non_temporal : engines.temporal; return engine->Compute(dst, src, length, initial_crc); } // For testing only: get an architecture-specific engine for tests. static std::unique_ptr GetTestEngine(int vector, int integer); private: struct ArchSpecificEngines { CrcMemcpyEngine* temporal; CrcMemcpyEngine* non_temporal; }; static ArchSpecificEngines GetArchSpecificEngines(); }; // Fallback CRC-memcpy engine. class FallbackCrcMemcpyEngine : public CrcMemcpyEngine { public: FallbackCrcMemcpyEngine() = default; FallbackCrcMemcpyEngine(const FallbackCrcMemcpyEngine&) = delete; FallbackCrcMemcpyEngine operator=(const FallbackCrcMemcpyEngine&) = delete; crc32c_t Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const override; }; // CRC Non-Temporal-Memcpy engine. class CrcNonTemporalMemcpyEngine : public CrcMemcpyEngine { public: CrcNonTemporalMemcpyEngine() = default; CrcNonTemporalMemcpyEngine(const CrcNonTemporalMemcpyEngine&) = delete; CrcNonTemporalMemcpyEngine operator=(const CrcNonTemporalMemcpyEngine&) = delete; crc32c_t Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const override; }; // CRC Non-Temporal-Memcpy AVX engine. class CrcNonTemporalMemcpyAVXEngine : public CrcMemcpyEngine { public: CrcNonTemporalMemcpyAVXEngine() = default; CrcNonTemporalMemcpyAVXEngine(const CrcNonTemporalMemcpyAVXEngine&) = delete; CrcNonTemporalMemcpyAVXEngine operator=( const CrcNonTemporalMemcpyAVXEngine&) = delete; crc32c_t Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const override; }; // Copy source to destination and return the CRC32C of the data copied. If an // accelerated version is available, use the accelerated version, otherwise use // the generic fallback version. inline crc32c_t Crc32CAndCopy(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc = crc32c_t{0}, bool non_temporal = false) { return CrcMemcpy::CrcAndCopy(dst, src, length, initial_crc, non_temporal); } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC_MEMCPY_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h0000644000175000017510000001777614737212474026253 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ #define ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ #include #include "absl/base/config.h" // ------------------------------------------------------------------------- // Many x86 and ARM machines have CRC acceleration hardware. // We can do a faster version of Extend() on such machines. // We define a translation layer for both x86 and ARM for the ease of use and // most performance gains. // This implementation requires 64-bit CRC instructions (part of SSE 4.2) and // PCLMULQDQ instructions. 32-bit builds with SSE 4.2 do exist, so the // __x86_64__ condition is necessary. #if defined(__x86_64__) && defined(__SSE4_2__) && defined(__PCLMUL__) #include #define ABSL_CRC_INTERNAL_HAVE_X86_SIMD #elif defined(_MSC_VER) && !defined(__clang__) && defined(__AVX__) // MSVC AVX (/arch:AVX) implies SSE 4.2 and PCLMULQDQ. #include #define ABSL_CRC_INTERNAL_HAVE_X86_SIMD #elif defined(__aarch64__) && defined(__LITTLE_ENDIAN__) && \ defined(__ARM_FEATURE_CRC32) && defined(ABSL_INTERNAL_HAVE_ARM_NEON) && \ defined(__ARM_FEATURE_CRYPTO) #include #include #define ABSL_CRC_INTERNAL_HAVE_ARM_SIMD #endif namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \ defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) #if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) using V128 = uint64x2_t; #else using V128 = __m128i; #endif // Starting with the initial value in |crc|, accumulates a CRC32 value for // unsigned integers of different sizes. uint32_t CRC32_u8(uint32_t crc, uint8_t v); uint32_t CRC32_u16(uint32_t crc, uint16_t v); uint32_t CRC32_u32(uint32_t crc, uint32_t v); uint32_t CRC32_u64(uint32_t crc, uint64_t v); // Loads 128 bits of integer data. |src| must be 16-byte aligned. V128 V128_Load(const V128* src); // Load 128 bits of integer data. |src| does not need to be aligned. V128 V128_LoadU(const V128* src); // Polynomially multiplies the high 64 bits of |l| and |r|. V128 V128_PMulHi(const V128 l, const V128 r); // Polynomially multiplies the low 64 bits of |l| and |r|. V128 V128_PMulLow(const V128 l, const V128 r); // Polynomially multiplies the low 64 bits of |r| and high 64 bits of |l|. V128 V128_PMul01(const V128 l, const V128 r); // Polynomially multiplies the low 64 bits of |l| and high 64 bits of |r|. V128 V128_PMul10(const V128 l, const V128 r); // Produces a XOR operation of |l| and |r|. V128 V128_Xor(const V128 l, const V128 r); // Produces an AND operation of |l| and |r|. V128 V128_And(const V128 l, const V128 r); // Sets two 64 bit integers to one 128 bit vector. The order is reverse. // dst[63:0] := |r| // dst[127:64] := |l| V128 V128_From2x64(const uint64_t l, const uint64_t r); // Shift |l| right by |imm| bytes while shifting in zeros. template V128 V128_ShiftRight(const V128 l); // Extracts a 32-bit integer from |l|, selected with |imm|. template int V128_Extract32(const V128 l); // Extracts the low 64 bits from V128. int64_t V128_Low64(const V128 l); // Left-shifts packed 64-bit integers in l by r. V128 V128_ShiftLeft64(const V128 l, const V128 r); #endif #if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD) inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { return _mm_crc32_u8(crc, v); } inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) { return _mm_crc32_u16(crc, v); } inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) { return _mm_crc32_u32(crc, v); } inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) { return static_cast(_mm_crc32_u64(crc, v)); } inline V128 V128_Load(const V128* src) { return _mm_load_si128(src); } inline V128 V128_LoadU(const V128* src) { return _mm_loadu_si128(src); } inline V128 V128_PMulHi(const V128 l, const V128 r) { return _mm_clmulepi64_si128(l, r, 0x11); } inline V128 V128_PMulLow(const V128 l, const V128 r) { return _mm_clmulepi64_si128(l, r, 0x00); } inline V128 V128_PMul01(const V128 l, const V128 r) { return _mm_clmulepi64_si128(l, r, 0x01); } inline V128 V128_PMul10(const V128 l, const V128 r) { return _mm_clmulepi64_si128(l, r, 0x10); } inline V128 V128_Xor(const V128 l, const V128 r) { return _mm_xor_si128(l, r); } inline V128 V128_And(const V128 l, const V128 r) { return _mm_and_si128(l, r); } inline V128 V128_From2x64(const uint64_t l, const uint64_t r) { return _mm_set_epi64x(static_cast(l), static_cast(r)); } template inline V128 V128_ShiftRight(const V128 l) { return _mm_srli_si128(l, imm); } template inline int V128_Extract32(const V128 l) { return _mm_extract_epi32(l, imm); } inline int64_t V128_Low64(const V128 l) { return _mm_cvtsi128_si64(l); } inline V128 V128_ShiftLeft64(const V128 l, const V128 r) { return _mm_sll_epi64(l, r); } #elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { return __crc32cb(crc, v); } inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) { return __crc32ch(crc, v); } inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) { return __crc32cw(crc, v); } inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) { return __crc32cd(crc, v); } inline V128 V128_Load(const V128* src) { return vld1q_u64(reinterpret_cast(src)); } inline V128 V128_LoadU(const V128* src) { return vld1q_u64(reinterpret_cast(src)); } // Using inline assembly as clang does not generate the pmull2 instruction and // performance drops by 15-20%. // TODO(b/193678732): Investigate why the compiler decides not to generate // such instructions and why it becomes so much worse. inline V128 V128_PMulHi(const V128 l, const V128 r) { uint64x2_t res; __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(res) : "w"(l), "w"(r)); return res; } inline V128 V128_PMulLow(const V128 l, const V128 r) { return reinterpret_cast(vmull_p64( reinterpret_cast(vget_low_p64(vreinterpretq_p64_u64(l))), reinterpret_cast(vget_low_p64(vreinterpretq_p64_u64(r))))); } inline V128 V128_PMul01(const V128 l, const V128 r) { return reinterpret_cast(vmull_p64( reinterpret_cast(vget_high_p64(vreinterpretq_p64_u64(l))), reinterpret_cast(vget_low_p64(vreinterpretq_p64_u64(r))))); } inline V128 V128_PMul10(const V128 l, const V128 r) { return reinterpret_cast(vmull_p64( reinterpret_cast(vget_low_p64(vreinterpretq_p64_u64(l))), reinterpret_cast(vget_high_p64(vreinterpretq_p64_u64(r))))); } inline V128 V128_Xor(const V128 l, const V128 r) { return veorq_u64(l, r); } inline V128 V128_And(const V128 l, const V128 r) { return vandq_u64(l, r); } inline V128 V128_From2x64(const uint64_t l, const uint64_t r) { return vcombine_u64(vcreate_u64(r), vcreate_u64(l)); } template inline V128 V128_ShiftRight(const V128 l) { return vreinterpretq_u64_s8( vextq_s8(vreinterpretq_s8_u64(l), vdupq_n_s8(0), imm)); } template inline int V128_Extract32(const V128 l) { return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm); } inline int64_t V128_Low64(const V128 l) { return vgetq_lane_s64(vreinterpretq_s64_u64(l), 0); } inline V128 V128_ShiftLeft64(const V128 l, const V128 r) { return vshlq_u64(l, vreinterpretq_s64_u64(r)); } #endif } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_cord_state.cc0000644000175000017510000000733614737212474024222 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/crc/internal/crc_cord_state.h" #include #include "absl/base/config.h" #include "absl/numeric/bits.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { CrcCordState::RefcountedRep* CrcCordState::RefSharedEmptyRep() { static CrcCordState::RefcountedRep* empty = new CrcCordState::RefcountedRep; assert(empty->count.load(std::memory_order_relaxed) >= 1); assert(empty->rep.removed_prefix.length == 0); assert(empty->rep.prefix_crc.empty()); Ref(empty); return empty; } CrcCordState::CrcCordState() : refcounted_rep_(new RefcountedRep) {} CrcCordState::CrcCordState(const CrcCordState& other) : refcounted_rep_(other.refcounted_rep_) { Ref(refcounted_rep_); } CrcCordState::CrcCordState(CrcCordState&& other) : refcounted_rep_(other.refcounted_rep_) { // Make `other` valid for use after move. other.refcounted_rep_ = RefSharedEmptyRep(); } CrcCordState& CrcCordState::operator=(const CrcCordState& other) { if (this != &other) { Unref(refcounted_rep_); refcounted_rep_ = other.refcounted_rep_; Ref(refcounted_rep_); } return *this; } CrcCordState& CrcCordState::operator=(CrcCordState&& other) { if (this != &other) { Unref(refcounted_rep_); refcounted_rep_ = other.refcounted_rep_; // Make `other` valid for use after move. other.refcounted_rep_ = RefSharedEmptyRep(); } return *this; } CrcCordState::~CrcCordState() { Unref(refcounted_rep_); } crc32c_t CrcCordState::Checksum() const { if (rep().prefix_crc.empty()) { return absl::crc32c_t{0}; } if (IsNormalized()) { return rep().prefix_crc.back().crc; } return absl::RemoveCrc32cPrefix( rep().removed_prefix.crc, rep().prefix_crc.back().crc, rep().prefix_crc.back().length - rep().removed_prefix.length); } CrcCordState::PrefixCrc CrcCordState::NormalizedPrefixCrcAtNthChunk( size_t n) const { assert(n < NumChunks()); if (IsNormalized()) { return rep().prefix_crc[n]; } size_t length = rep().prefix_crc[n].length - rep().removed_prefix.length; return PrefixCrc(length, absl::RemoveCrc32cPrefix(rep().removed_prefix.crc, rep().prefix_crc[n].crc, length)); } void CrcCordState::Normalize() { if (IsNormalized() || rep().prefix_crc.empty()) { return; } Rep* r = mutable_rep(); for (auto& prefix_crc : r->prefix_crc) { size_t remaining = prefix_crc.length - r->removed_prefix.length; prefix_crc.crc = absl::RemoveCrc32cPrefix(r->removed_prefix.crc, prefix_crc.crc, remaining); prefix_crc.length = remaining; } r->removed_prefix = PrefixCrc(); } void CrcCordState::Poison() { Rep* rep = mutable_rep(); if (NumChunks() > 0) { for (auto& prefix_crc : rep->prefix_crc) { // This is basically CRC32::Scramble(). uint32_t crc = static_cast(prefix_crc.crc); crc += 0x2e76e41b; crc = absl::rotr(crc, 17); prefix_crc.crc = crc32c_t{crc}; } } else { // Add a fake corrupt chunk. rep->prefix_crc.emplace_back(0, crc32c_t{1}); } } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_internal.h0000644000175000017510000001563314737212474023550 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC_INTERNAL_H_ #define ABSL_CRC_INTERNAL_CRC_INTERNAL_H_ #include #include #include #include "absl/base/internal/raw_logging.h" #include "absl/crc/internal/crc.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // Prefetch constants used in some Extend() implementations constexpr int kPrefetchHorizon = ABSL_CACHELINE_SIZE * 4; // Prefetch this far // Shorter prefetch distance for smaller buffers constexpr int kPrefetchHorizonMedium = ABSL_CACHELINE_SIZE * 1; static_assert(kPrefetchHorizon >= 64, "CRCPrefetchHorizon less than loop len"); // We require the Scramble() function: // - to be reversible (Unscramble() must exist) // - to be non-linear in the polynomial's Galois field (so the CRC of a // scrambled CRC is not linearly affected by the scrambled CRC, even if // using the same polynomial) // - not to be its own inverse. Preferably, if X=Scramble^N(X) and N!=0, then // N is large. // - to be fast. // - not to change once defined. // We introduce non-linearity in two ways: // Addition of a constant. // - The carries introduce non-linearity; we use bits of an irrational // (phi) to make it unlikely that we introduce no carries. // Rotate by a constant number of bits. // - We use floor(degree/2)+1, which does not divide the degree, and // splits the bits nearly evenly, which makes it less likely the // halves will be the same or one will be all zeroes. // We do both things to improve the chances of non-linearity in the face of // bit patterns with low numbers of bits set, while still being fast. // Below is the constant that we add. The bits are the first 128 bits of the // fractional part of phi, with a 1 ored into the bottom bit to maximize the // cycle length of repeated adds. constexpr uint64_t kScrambleHi = (static_cast(0x4f1bbcdcU) << 32) | static_cast(0xbfa53e0aU); constexpr uint64_t kScrambleLo = (static_cast(0xf9ce6030U) << 32) | static_cast(0x2e76e41bU); class CRCImpl : public CRC { // Implementation of the abstract class CRC public: using Uint32By256 = uint32_t[256]; CRCImpl() = default; ~CRCImpl() override = default; // The internal version of CRC::New(). static CRCImpl* NewInternal(); // Fill in a table for updating a CRC by one word of 'word_size' bytes // [last_lo, last_hi] contains the answer if the last bit in the word // is set. static void FillWordTable(uint32_t poly, uint32_t last, int word_size, Uint32By256* t); // Build the table for extending by zeroes, returning the number of entries. // For a in {1, 2, ..., ZEROES_BASE-1}, b in {0, 1, 2, 3, ...}, // entry j=a-1+(ZEROES_BASE-1)*b // contains a polynomial Pi such that multiplying // a CRC by Pi mod P, where P is the CRC polynomial, is equivalent to // appending a*2**(ZEROES_BASE_LG*b) zero bytes to the original string. static int FillZeroesTable(uint32_t poly, Uint32By256* t); virtual void InitTables() = 0; private: CRCImpl(const CRCImpl&) = delete; CRCImpl& operator=(const CRCImpl&) = delete; }; // This is the 32-bit implementation. It handles all sizes from 8 to 32. class CRC32 : public CRCImpl { public: CRC32() = default; ~CRC32() override = default; void Extend(uint32_t* crc, const void* bytes, size_t length) const override; void ExtendByZeroes(uint32_t* crc, size_t length) const override; void Scramble(uint32_t* crc) const override; void Unscramble(uint32_t* crc) const override; void UnextendByZeroes(uint32_t* crc, size_t length) const override; void InitTables() override; private: // Common implementation guts for ExtendByZeroes and UnextendByZeroes(). // // zeroes_table is a table as returned by FillZeroesTable(), containing // polynomials representing CRCs of strings-of-zeros of various lengths, // and which can be combined by polynomial multiplication. poly_table is // a table of CRC byte extension values. These tables are determined by // the generator polynomial. // // These will be set to reverse_zeroes_ and reverse_table0_ for Unextend, and // CRC32::zeroes_ and CRC32::table0_ for Extend. static void ExtendByZeroesImpl(uint32_t* crc, size_t length, const uint32_t zeroes_table[256], const uint32_t poly_table[256]); uint32_t table0_[256]; // table of byte extensions uint32_t zeroes_[256]; // table of zero extensions // table of 4-byte extensions shifted by 12 bytes of zeroes uint32_t table_[4][256]; // Reverse lookup tables, using the alternate polynomial used by // UnextendByZeroes(). uint32_t reverse_table0_[256]; // table of reverse byte extensions uint32_t reverse_zeroes_[256]; // table of reverse zero extensions CRC32(const CRC32&) = delete; CRC32& operator=(const CRC32&) = delete; }; // Helpers // Return a bit mask containing len 1-bits. // Requires 0 < len <= sizeof(T) template T MaskOfLength(int len) { // shift 2 by len-1 rather than 1 by len because shifts of wordsize // are undefined. return (T(2) << (len - 1)) - 1; } // Rotate low-order "width" bits of "in" right by "r" bits, // setting other bits in word to arbitrary values. template T RotateRight(T in, int width, int r) { return (in << (width - r)) | ((in >> r) & MaskOfLength(width - r)); } // RoundUp(p) returns the lowest address >= p aligned to an N-byte // boundary. Requires that N is a power of 2. template const uint8_t* RoundUp(const uint8_t* p) { static_assert((alignment & (alignment - 1)) == 0, "alignment is not 2^n"); constexpr uintptr_t mask = alignment - 1; const uintptr_t as_uintptr = reinterpret_cast(p); return reinterpret_cast((as_uintptr + mask) & ~mask); } // Return a newly created CRC32AcceleratedX86ARMCombined if we can use Intel's // or ARM's CRC acceleration for a given polynomial. Return nullptr otherwise. CRCImpl* TryNewCRC32AcceleratedX86ARMCombined(); // Return all possible hardware accelerated implementations. For testing only. std::vector> NewCRC32AcceleratedX86ARMCombinedAll(); } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC_INTERNAL_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc_non_temporal_memcpy.cc0000644000175000017510000000644514737212474026142 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "absl/base/config.h" #include "absl/crc/crc32c.h" #include "absl/crc/internal/crc_memcpy.h" #include "absl/crc/internal/non_temporal_memcpy.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { crc32c_t CrcNonTemporalMemcpyEngine::Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const { constexpr size_t kBlockSize = 8192; crc32c_t crc = initial_crc; const char* src_bytes = reinterpret_cast(src); char* dst_bytes = reinterpret_cast(dst); // Copy + CRC loop - run 8k chunks until we are out of full chunks. std::size_t offset = 0; for (; offset + kBlockSize < length; offset += kBlockSize) { crc = absl::ExtendCrc32c(crc, absl::string_view(src_bytes + offset, kBlockSize)); non_temporal_store_memcpy(dst_bytes + offset, src_bytes + offset, kBlockSize); } // Save some work if length is 0. if (offset < length) { std::size_t final_copy_size = length - offset; crc = ExtendCrc32c(crc, absl::string_view(src_bytes + offset, final_copy_size)); non_temporal_store_memcpy(dst_bytes + offset, src_bytes + offset, final_copy_size); } return crc; } crc32c_t CrcNonTemporalMemcpyAVXEngine::Compute(void* __restrict dst, const void* __restrict src, std::size_t length, crc32c_t initial_crc) const { constexpr size_t kBlockSize = 8192; crc32c_t crc = initial_crc; const char* src_bytes = reinterpret_cast(src); char* dst_bytes = reinterpret_cast(dst); // Copy + CRC loop - run 8k chunks until we are out of full chunks. std::size_t offset = 0; for (; offset + kBlockSize < length; offset += kBlockSize) { crc = ExtendCrc32c(crc, absl::string_view(src_bytes + offset, kBlockSize)); non_temporal_store_memcpy_avx(dst_bytes + offset, src_bytes + offset, kBlockSize); } // Save some work if length is 0. if (offset < length) { std::size_t final_copy_size = length - offset; crc = ExtendCrc32c(crc, absl::string_view(src_bytes + offset, final_copy_size)); non_temporal_store_memcpy_avx(dst_bytes + offset, src_bytes + offset, final_copy_size); } return crc; } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/crc.cc0000644000175000017510000003542714737212474022015 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Implementation of CRCs (aka Rabin Fingerprints). // Treats the input as a polynomial with coefficients in Z(2), // and finds the remainder when divided by an irreducible polynomial // of the appropriate length. // It handles all CRC sizes from 8 to 128 bits. // It's somewhat complicated by having separate implementations optimized for // CRC's <=32 bits, <= 64 bits, and <= 128 bits. // The input string is prefixed with a "1" bit, and has "degree" "0" bits // appended to it before the remainder is found. This ensures that // short strings are scrambled somewhat and that strings consisting // of all nulls have a non-zero CRC. // // Uses the "interleaved word-by-word" method from // "Everything we know about CRC but afraid to forget" by Andrew Kadatch // and Bob Jenkins, // http://crcutil.googlecode.com/files/crc-doc.1.0.pdf // // The idea is to compute kStride CRCs simultaneously, allowing the // processor to more effectively use multiple execution units. Each of // the CRCs is calculated on one word of data followed by kStride - 1 // words of zeroes; the CRC starting points are staggered by one word. // Assuming a stride of 4 with data words "ABCDABCDABCD", the first // CRC is over A000A000A, the second over 0B000B000B, and so on. // The CRC of the whole data is then calculated by properly aligning the // CRCs by appending zeroes until the data lengths agree then XORing // the CRCs. #include "absl/crc/internal/crc.h" #include #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/prefetch.h" #include "absl/crc/internal/crc_internal.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { namespace { // Constants #if defined(__i386__) || defined(__x86_64__) constexpr bool kNeedAlignedLoads = false; #else constexpr bool kNeedAlignedLoads = true; #endif // We express the number of zeroes as a number in base ZEROES_BASE. By // pre-computing the zero extensions for all possible components of such an // expression (numbers in a form a*ZEROES_BASE**b), we can calculate the // resulting extension by multiplying the extensions for individual components // using log_{ZEROES_BASE}(num_zeroes) polynomial multiplications. The tables of // zero extensions contain (ZEROES_BASE - 1) * (log_{ZEROES_BASE}(64)) entries. constexpr int ZEROES_BASE_LG = 4; // log_2(ZEROES_BASE) constexpr int ZEROES_BASE = (1 << ZEROES_BASE_LG); // must be a power of 2 constexpr uint32_t kCrc32cPoly = 0x82f63b78; uint32_t ReverseBits(uint32_t bits) { bits = (bits & 0xaaaaaaaau) >> 1 | (bits & 0x55555555u) << 1; bits = (bits & 0xccccccccu) >> 2 | (bits & 0x33333333u) << 2; bits = (bits & 0xf0f0f0f0u) >> 4 | (bits & 0x0f0f0f0fu) << 4; return absl::gbswap_32(bits); } // Polynomial long multiplication mod the polynomial of degree 32. void PolyMultiply(uint32_t* val, uint32_t m, uint32_t poly) { uint32_t l = *val; uint32_t result = 0; auto onebit = uint32_t{0x80000000u}; for (uint32_t one = onebit; one != 0; one >>= 1) { if ((l & one) != 0) { result ^= m; } if (m & 1) { m = (m >> 1) ^ poly; } else { m >>= 1; } } *val = result; } } // namespace void CRCImpl::FillWordTable(uint32_t poly, uint32_t last, int word_size, Uint32By256* t) { for (int j = 0; j != word_size; j++) { // for each byte of extension.... t[j][0] = 0; // a zero has no effect for (int i = 128; i != 0; i >>= 1) { // fill in entries for powers of 2 if (j == 0 && i == 128) { t[j][i] = last; // top bit in last byte is given } else { // each successive power of two is derived from the previous // one, either in this table, or the last table uint32_t pred; if (i == 128) { pred = t[j - 1][1]; } else { pred = t[j][i << 1]; } // Advance the CRC by one bit (multiply by X, and take remainder // through one step of polynomial long division) if (pred & 1) { t[j][i] = (pred >> 1) ^ poly; } else { t[j][i] = pred >> 1; } } } // CRCs have the property that CRC(a xor b) == CRC(a) xor CRC(b) // so we can make all the tables for non-powers of two by // xoring previously created entries. for (int i = 2; i != 256; i <<= 1) { for (int k = i + 1; k != (i << 1); k++) { t[j][k] = t[j][i] ^ t[j][k - i]; } } } } int CRCImpl::FillZeroesTable(uint32_t poly, Uint32By256* t) { uint32_t inc = 1; inc <<= 31; // Extend by one zero bit. We know degree > 1 so (inc & 1) == 0. inc >>= 1; // Now extend by 2, 4, and 8 bits, so now `inc` is extended by one zero byte. for (int i = 0; i < 3; ++i) { PolyMultiply(&inc, inc, poly); } int j = 0; for (uint64_t inc_len = 1; inc_len != 0; inc_len <<= ZEROES_BASE_LG) { // Every entry in the table adds an additional inc_len zeroes. uint32_t v = inc; for (int a = 1; a != ZEROES_BASE; a++) { t[0][j] = v; PolyMultiply(&v, inc, poly); j++; } inc = v; } ABSL_RAW_CHECK(j <= 256, ""); return j; } // Internal version of the "constructor". CRCImpl* CRCImpl::NewInternal() { // Find an accelearated implementation first. CRCImpl* result = TryNewCRC32AcceleratedX86ARMCombined(); // Fall back to generic implementions if no acceleration is available. if (result == nullptr) { result = new CRC32(); } result->InitTables(); return result; } // The 32-bit implementation void CRC32::InitTables() { // Compute the table for extending a CRC by one byte. Uint32By256* t = new Uint32By256[4]; FillWordTable(kCrc32cPoly, kCrc32cPoly, 1, t); for (int i = 0; i != 256; i++) { this->table0_[i] = t[0][i]; } // Construct a table for updating the CRC by 4 bytes data followed by // 12 bytes of zeroes. // // Note: the data word size could be larger than the CRC size; it might // be slightly faster to use a 64-bit data word, but doing so doubles the // table size. uint32_t last = kCrc32cPoly; const size_t size = 12; for (size_t i = 0; i < size; ++i) { last = (last >> 8) ^ this->table0_[last & 0xff]; } FillWordTable(kCrc32cPoly, last, 4, t); for (size_t b = 0; b < 4; ++b) { for (int i = 0; i < 256; ++i) { this->table_[b][i] = t[b][i]; } } int j = FillZeroesTable(kCrc32cPoly, t); ABSL_RAW_CHECK(j <= static_cast(ABSL_ARRAYSIZE(this->zeroes_)), ""); for (int i = 0; i < j; i++) { this->zeroes_[i] = t[0][i]; } delete[] t; // Build up tables for _reversing_ the operation of doing CRC operations on // zero bytes. // In C++, extending `crc` by a single zero bit is done by the following: // (A) bool low_bit_set = (crc & 1); // crc >>= 1; // if (low_bit_set) crc ^= kCrc32cPoly; // // In particular note that the high bit of `crc` after this operation will be // set if and only if the low bit of `crc` was set before it. This means that // no information is lost, and the operation can be reversed, as follows: // (B) bool high_bit_set = (crc & 0x80000000u); // if (high_bit_set) crc ^= kCrc32cPoly; // crc <<= 1; // if (high_bit_set) crc ^= 1; // // Or, equivalently: // (C) bool high_bit_set = (crc & 0x80000000u); // crc <<= 1; // if (high_bit_set) crc ^= ((kCrc32cPoly << 1) ^ 1); // // The last observation is, if we store our checksums in variable `rcrc`, // with order of the bits reversed, the inverse operation becomes: // (D) bool low_bit_set = (rcrc & 1); // rcrc >>= 1; // if (low_bit_set) rcrc ^= ReverseBits((kCrc32cPoly << 1) ^ 1) // // This is the same algorithm (A) that we started with, only with a different // polynomial bit pattern. This means that by building up our tables with // this alternate polynomial, we can apply the CRC algorithms to a // bit-reversed CRC checksum to perform inverse zero-extension. const uint32_t kCrc32cUnextendPoly = ReverseBits(static_cast((kCrc32cPoly << 1) ^ 1)); FillWordTable(kCrc32cUnextendPoly, kCrc32cUnextendPoly, 1, &reverse_table0_); j = FillZeroesTable(kCrc32cUnextendPoly, &reverse_zeroes_); ABSL_RAW_CHECK(j <= static_cast(ABSL_ARRAYSIZE(this->reverse_zeroes_)), ""); } void CRC32::Extend(uint32_t* crc, const void* bytes, size_t length) const { const uint8_t* p = static_cast(bytes); const uint8_t* e = p + length; uint32_t l = *crc; auto step_one_byte = [this, &p, &l]() { int c = (l & 0xff) ^ *p++; l = this->table0_[c] ^ (l >> 8); }; if (kNeedAlignedLoads) { // point x at first 4-byte aligned byte in string. this might be past the // end of the string. const uint8_t* x = RoundUp<4>(p); if (x <= e) { // Process bytes until finished or p is 4-byte aligned while (p != x) { step_one_byte(); } } } const size_t kSwathSize = 16; if (static_cast(e - p) >= kSwathSize) { // Load one swath of data into the operating buffers. uint32_t buf0 = absl::little_endian::Load32(p) ^ l; uint32_t buf1 = absl::little_endian::Load32(p + 4); uint32_t buf2 = absl::little_endian::Load32(p + 8); uint32_t buf3 = absl::little_endian::Load32(p + 12); p += kSwathSize; // Increment a CRC value by a "swath"; this combines the four bytes // starting at `ptr` and twelve zero bytes, so that four CRCs can be // built incrementally and combined at the end. const auto step_swath = [this](uint32_t crc_in, const std::uint8_t* ptr) { return absl::little_endian::Load32(ptr) ^ this->table_[3][crc_in & 0xff] ^ this->table_[2][(crc_in >> 8) & 0xff] ^ this->table_[1][(crc_in >> 16) & 0xff] ^ this->table_[0][crc_in >> 24]; }; // Run one CRC calculation step over all swaths in one 16-byte stride const auto step_stride = [&]() { buf0 = step_swath(buf0, p); buf1 = step_swath(buf1, p + 4); buf2 = step_swath(buf2, p + 8); buf3 = step_swath(buf3, p + 12); p += 16; }; // Process kStride interleaved swaths through the data in parallel. while ((e - p) > kPrefetchHorizon) { PrefetchToLocalCacheNta( reinterpret_cast(p + kPrefetchHorizon)); // Process 64 bytes at a time step_stride(); step_stride(); step_stride(); step_stride(); } while (static_cast(e - p) >= kSwathSize) { step_stride(); } // Now advance one word at a time as far as possible. This isn't worth // doing if we have word-advance tables. while (static_cast(e - p) >= 4) { buf0 = step_swath(buf0, p); uint32_t tmp = buf0; buf0 = buf1; buf1 = buf2; buf2 = buf3; buf3 = tmp; p += 4; } // Combine the results from the different swaths. This is just a CRC // on the data values in the bufX words. auto combine_one_word = [this](uint32_t crc_in, uint32_t w) { w ^= crc_in; for (size_t i = 0; i < 4; ++i) { w = (w >> 8) ^ this->table0_[w & 0xff]; } return w; }; l = combine_one_word(0, buf0); l = combine_one_word(l, buf1); l = combine_one_word(l, buf2); l = combine_one_word(l, buf3); } // Process the last few bytes while (p != e) { step_one_byte(); } *crc = l; } void CRC32::ExtendByZeroesImpl(uint32_t* crc, size_t length, const uint32_t zeroes_table[256], const uint32_t poly_table[256]) { if (length != 0) { uint32_t l = *crc; // For each ZEROES_BASE_LG bits in length // (after the low-order bits have been removed) // we lookup the appropriate polynomial in the zeroes_ array // and do a polynomial long multiplication (mod the CRC polynomial) // to extend the CRC by the appropriate number of bits. for (int i = 0; length != 0; i += ZEROES_BASE - 1, length >>= ZEROES_BASE_LG) { int c = length & (ZEROES_BASE - 1); // pick next ZEROES_BASE_LG bits if (c != 0) { // if they are not zero, // multiply by entry in table // Build a table to aid in multiplying 2 bits at a time. // It takes too long to build tables for more bits. uint64_t m = zeroes_table[c + i - 1]; m <<= 1; uint64_t m2 = m << 1; uint64_t mtab[4] = {0, m, m2, m2 ^ m}; // Do the multiply one byte at a time. uint64_t result = 0; for (int x = 0; x < 32; x += 8) { // The carry-less multiply. result ^= mtab[l & 3] ^ (mtab[(l >> 2) & 3] << 2) ^ (mtab[(l >> 4) & 3] << 4) ^ (mtab[(l >> 6) & 3] << 6); l >>= 8; // Reduce modulo the polynomial result = (result >> 8) ^ poly_table[result & 0xff]; } l = static_cast(result); } } *crc = l; } } void CRC32::ExtendByZeroes(uint32_t* crc, size_t length) const { return CRC32::ExtendByZeroesImpl(crc, length, zeroes_, table0_); } void CRC32::UnextendByZeroes(uint32_t* crc, size_t length) const { // See the comment in CRC32::InitTables() for an explanation of the algorithm // below. *crc = ReverseBits(*crc); ExtendByZeroesImpl(crc, length, reverse_zeroes_, reverse_table0_); *crc = ReverseBits(*crc); } void CRC32::Scramble(uint32_t* crc) const { // Rotate by near half the word size plus 1. See the scramble comment in // crc_internal.h for an explanation. constexpr int scramble_rotate = (32 / 2) + 1; *crc = RotateRight(static_cast(*crc + kScrambleLo), 32, scramble_rotate) & MaskOfLength(32); } void CRC32::Unscramble(uint32_t* crc) const { constexpr int scramble_rotate = (32 / 2) + 1; uint64_t rotated = RotateRight(static_cast(*crc), 32, 32 - scramble_rotate); *crc = (rotated - kScrambleLo) & MaskOfLength(32); } // Constructor and destructor for base class CRC. CRC::~CRC() {} CRC::CRC() {} // The "constructor" for a CRC32C with a standard polynomial. CRC* CRC::Crc32c() { static CRC* singleton = CRCImpl::NewInternal(); return singleton; } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/internal/non_temporal_memcpy.h0000644000175000017510000001333214737212474025146 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_ #define ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_ #ifdef _MSC_VER #include #endif #ifdef __SSE__ #include #endif #ifdef __SSE2__ #include #endif #ifdef __SSE3__ #include #endif #ifdef __AVX__ #include #endif #ifdef __aarch64__ #include "absl/crc/internal/non_temporal_arm_intrinsics.h" #endif #include #include #include #include #include "absl/base/config.h" #include "absl/base/optimization.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { // This non-temporal memcpy does regular load and non-temporal store memory // copy. It is compatible to both 16-byte aligned and unaligned addresses. If // data at the destination is not immediately accessed, using non-temporal // memcpy can save 1 DRAM load of the destination cacheline. constexpr size_t kCacheLineSize = ABSL_CACHELINE_SIZE; // If the objects overlap, the behavior is undefined. inline void *non_temporal_store_memcpy(void *__restrict dst, const void *__restrict src, size_t len) { #if defined(__SSE3__) || defined(__aarch64__) || \ (defined(_MSC_VER) && defined(__AVX__)) // This implementation requires SSE3. // MSVC cannot target SSE3 directly, but when MSVC targets AVX, // SSE3 support is implied. uint8_t *d = reinterpret_cast(dst); const uint8_t *s = reinterpret_cast(src); // memcpy() the misaligned header. At the end of this if block, is // aligned to a 64-byte cacheline boundary or == 0. if (reinterpret_cast(d) & (kCacheLineSize - 1)) { uintptr_t bytes_before_alignment_boundary = kCacheLineSize - (reinterpret_cast(d) & (kCacheLineSize - 1)); size_t header_len = (std::min)(bytes_before_alignment_boundary, len); assert(bytes_before_alignment_boundary < kCacheLineSize); memcpy(d, s, header_len); d += header_len; s += header_len; len -= header_len; } if (len >= kCacheLineSize) { _mm_sfence(); __m128i *dst_cacheline = reinterpret_cast<__m128i *>(d); const __m128i *src_cacheline = reinterpret_cast(s); constexpr int kOpsPerCacheLine = kCacheLineSize / sizeof(__m128i); size_t loops = len / kCacheLineSize; while (len >= kCacheLineSize) { __m128i temp1, temp2, temp3, temp4; temp1 = _mm_lddqu_si128(src_cacheline + 0); temp2 = _mm_lddqu_si128(src_cacheline + 1); temp3 = _mm_lddqu_si128(src_cacheline + 2); temp4 = _mm_lddqu_si128(src_cacheline + 3); _mm_stream_si128(dst_cacheline + 0, temp1); _mm_stream_si128(dst_cacheline + 1, temp2); _mm_stream_si128(dst_cacheline + 2, temp3); _mm_stream_si128(dst_cacheline + 3, temp4); src_cacheline += kOpsPerCacheLine; dst_cacheline += kOpsPerCacheLine; len -= kCacheLineSize; } d += loops * kCacheLineSize; s += loops * kCacheLineSize; _mm_sfence(); } // memcpy the tail. if (len) { memcpy(d, s, len); } return dst; #else // Fallback to regular memcpy. return memcpy(dst, src, len); #endif // __SSE3__ || __aarch64__ || (_MSC_VER && __AVX__) } inline void *non_temporal_store_memcpy_avx(void *__restrict dst, const void *__restrict src, size_t len) { #ifdef __AVX__ uint8_t *d = reinterpret_cast(dst); const uint8_t *s = reinterpret_cast(src); // memcpy() the misaligned header. At the end of this if block, is // aligned to a 64-byte cacheline boundary or == 0. if (reinterpret_cast(d) & (kCacheLineSize - 1)) { uintptr_t bytes_before_alignment_boundary = kCacheLineSize - (reinterpret_cast(d) & (kCacheLineSize - 1)); size_t header_len = (std::min)(bytes_before_alignment_boundary, len); assert(bytes_before_alignment_boundary < kCacheLineSize); memcpy(d, s, header_len); d += header_len; s += header_len; len -= header_len; } if (len >= kCacheLineSize) { _mm_sfence(); __m256i *dst_cacheline = reinterpret_cast<__m256i *>(d); const __m256i *src_cacheline = reinterpret_cast(s); constexpr int kOpsPerCacheLine = kCacheLineSize / sizeof(__m256i); size_t loops = len / kCacheLineSize; while (len >= kCacheLineSize) { __m256i temp1, temp2; temp1 = _mm256_lddqu_si256(src_cacheline + 0); temp2 = _mm256_lddqu_si256(src_cacheline + 1); _mm256_stream_si256(dst_cacheline + 0, temp1); _mm256_stream_si256(dst_cacheline + 1, temp2); src_cacheline += kOpsPerCacheLine; dst_cacheline += kOpsPerCacheLine; len -= kCacheLineSize; } d += loops * kCacheLineSize; s += loops * kCacheLineSize; _mm_sfence(); } // memcpy the tail. if (len) { memcpy(d, s, len); } return dst; #else // Fallback to regular memcpy when AVX is not available. return memcpy(dst, src, len); #endif // __AVX__ } } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_NON_TEMPORAL_MEMCPY_H_ s2/tools/vendor/abseil-cpp/absl/crc/internal/crc.h0000644000175000017510000000602614737212474021650 0ustar nileshnilesh// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CRC_INTERNAL_CRC_H_ #define ABSL_CRC_INTERNAL_CRC_H_ #include #include "absl/base/config.h" // This class implements CRCs (aka Rabin Fingerprints). // Treats the input as a polynomial with coefficients in Z(2), // and finds the remainder when divided by an primitive polynomial // of the appropriate length. // A polynomial is represented by the bit pattern formed by its coefficients, // but with the highest order bit not stored. // The highest degree coefficient is stored in the lowest numbered bit // in the lowest addressed byte. Thus, in what follows, the highest degree // coefficient that is stored is in the low order bit of "lo" or "*lo". // Hardware acceleration is used when available. namespace absl { ABSL_NAMESPACE_BEGIN namespace crc_internal { class CRC { public: virtual ~CRC(); // If "*crc" is the CRC of bytestring A, place the CRC of // the bytestring formed from the concatenation of A and the "length" // bytes at "bytes" into "*crc". virtual void Extend(uint32_t* crc, const void* bytes, size_t length) const = 0; // Equivalent to Extend(crc, bytes, length) where "bytes" // points to an array of "length" zero bytes. virtual void ExtendByZeroes(uint32_t* crc, size_t length) const = 0; // Inverse operation of ExtendByZeroes. If `crc` is the CRC value of a string // ending in `length` zero bytes, this returns a CRC value of that string // with those zero bytes removed. virtual void UnextendByZeroes(uint32_t* crc, size_t length) const = 0; // Apply a non-linear transformation to "*crc" so that // it is safe to CRC the result with the same polynomial without // any reduction of error-detection ability in the outer CRC. // Unscramble() performs the inverse transformation. // It is strongly recommended that CRCs be scrambled before storage or // transmission, and unscrambled at the other end before further manipulation. virtual void Scramble(uint32_t* crc) const = 0; virtual void Unscramble(uint32_t* crc) const = 0; // Crc32c() returns the singleton implementation of CRC for the CRC32C // polynomial. Returns a handle that MUST NOT be destroyed with delete. static CRC* Crc32c(); protected: CRC(); // Clients may not call constructor; use Crc32c() instead. private: CRC(const CRC&) = delete; CRC& operator=(const CRC&) = delete; }; } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CRC_INTERNAL_CRC_H_ s2/tools/vendor/abseil-cpp/absl/crc/crc32c.cc0000644000175000017510000000643614737212474020507 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/crc/crc32c.h" #include #include "absl/crc/internal/crc.h" #include "absl/crc/internal/crc32c.h" #include "absl/crc/internal/crc_memcpy.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { const crc_internal::CRC* CrcEngine() { static const crc_internal::CRC* engine = crc_internal::CRC::Crc32c(); return engine; } constexpr uint32_t kCRC32Xor = 0xffffffffU; } // namespace namespace crc_internal { crc32c_t UnextendCrc32cByZeroes(crc32c_t initial_crc, size_t length) { uint32_t crc = static_cast(initial_crc) ^ kCRC32Xor; CrcEngine()->UnextendByZeroes(&crc, length); return static_cast(crc ^ kCRC32Xor); } // Called by `absl::ExtendCrc32c()` on strings with size > 64 or when hardware // CRC32C support is missing. crc32c_t ExtendCrc32cInternal(crc32c_t initial_crc, absl::string_view buf_to_add) { uint32_t crc = static_cast(initial_crc) ^ kCRC32Xor; CrcEngine()->Extend(&crc, buf_to_add.data(), buf_to_add.size()); return static_cast(crc ^ kCRC32Xor); } } // namespace crc_internal crc32c_t ComputeCrc32c(absl::string_view buf) { return ExtendCrc32c(crc32c_t{0}, buf); } crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length) { uint32_t crc = static_cast(initial_crc) ^ kCRC32Xor; CrcEngine()->ExtendByZeroes(&crc, length); return static_cast(crc ^ kCRC32Xor); } crc32c_t ConcatCrc32c(crc32c_t lhs_crc, crc32c_t rhs_crc, size_t rhs_len) { uint32_t result = static_cast(lhs_crc); CrcEngine()->ExtendByZeroes(&result, rhs_len); return crc32c_t{result ^ static_cast(rhs_crc)}; } crc32c_t RemoveCrc32cPrefix(crc32c_t crc_a, crc32c_t crc_ab, size_t length_b) { return ConcatCrc32c(crc_a, crc_ab, length_b); } crc32c_t MemcpyCrc32c(void* dest, const void* src, size_t count, crc32c_t initial_crc) { return static_cast( crc_internal::Crc32CAndCopy(dest, src, count, initial_crc, false)); } // Remove a Suffix of given size from a buffer // // Given a CRC32C of an existing buffer, `full_string_crc`; the CRC32C of a // suffix of that buffer to remove, `suffix_crc`; and suffix buffer's length, // `suffix_len` return the CRC32C of the buffer with suffix removed // // This operation has a runtime cost of O(log(`suffix_len`)) crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc, size_t suffix_len) { uint32_t result = static_cast(full_string_crc) ^ static_cast(suffix_crc); CrcEngine()->UnextendByZeroes(&result, suffix_len); return crc32c_t{result}; } ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/crc/CMakeLists.txt0000644000175000017510000000654314737212474021660 0ustar nileshnilesh# Copyright 2022 The Abseil Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Internal-only target, do not depend on directly. absl_cc_library( NAME crc_cpu_detect HDRS "internal/cpu_detect.h" SRCS "internal/cpu_detect.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::base absl::config ) # Internal-only target, do not depend on directly. absl_cc_library( NAME crc_internal HDRS "internal/crc.h" "internal/crc32_x86_arm_combined_simd.h" SRCS "internal/crc.cc" "internal/crc_internal.h" "internal/crc_x86_arm_combined.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc_cpu_detect absl::base absl::config absl::core_headers absl::dynamic_annotations absl::endian absl::prefetch absl::raw_logging_internal absl::memory absl::bits ) absl_cc_library( NAME crc32c HDRS "crc32c.h" "internal/crc32c.h" "internal/crc_memcpy.h" SRCS "crc32c.cc" "internal/crc32c_inline.h" "internal/crc_memcpy_fallback.cc" "internal/crc_memcpy_x86_64.cc" "internal/crc_non_temporal_memcpy.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc_cpu_detect absl::crc_internal absl::non_temporal_memcpy absl::config absl::core_headers absl::dynamic_annotations absl::endian absl::prefetch absl::str_format absl::strings ) absl_cc_test( NAME crc32c_test SRCS "crc32c_test.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc32c absl::strings absl::str_format GTest::gtest_main ) # Internal-only target, do not depend on directly. absl_cc_library( NAME non_temporal_arm_intrinsics HDRS "internal/non_temporal_arm_intrinsics.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::config ) # Internal-only target, do not depend on directly. absl_cc_library( NAME non_temporal_memcpy HDRS "internal/non_temporal_memcpy.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::non_temporal_arm_intrinsics absl::config absl::core_headers ) absl_cc_test( NAME crc_memcpy_test SRCS "internal/crc_memcpy_test.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc32c absl::memory absl::random_random absl::random_distributions absl::strings GTest::gtest_main ) absl_cc_test( NAME non_temporal_memcpy_test SRCS "internal/non_temporal_memcpy_test.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::non_temporal_memcpy GTest::gtest_main ) absl_cc_library( NAME crc_cord_state HDRS "internal/crc_cord_state.h" SRCS "internal/crc_cord_state.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc32c absl::config absl::strings ) absl_cc_test( NAME crc_cord_state_test SRCS "internal/crc_cord_state_test.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::crc_cord_state absl::crc32c GTest::gtest_main ) s2/tools/vendor/abseil-cpp/absl/abseil.podspec.gen.py0000644000175000017510000001643414737212474022366 0ustar nileshnilesh#!/usr/bin/env python3 # -*- coding: utf-8 -*- """This script generates abseil.podspec from all BUILD.bazel files. This is expected to run on abseil git repository with Bazel 1.0 on Linux. It recursively analyzes BUILD.bazel files using query command of Bazel to dump its build rules in XML format. From these rules, it constructs podspec structure. """ import argparse import collections import os import re import subprocess import xml.etree.ElementTree # Template of root podspec. SPEC_TEMPLATE = """ # This file has been automatically generated from a script. # Please make modifications to `abseil.podspec.gen.py` instead. Pod::Spec.new do |s| s.name = 'abseil' s.version = '${version}' s.summary = 'Abseil Common Libraries (C++) from Google' s.homepage = 'https://abseil.io' s.license = 'Apache License, Version 2.0' s.authors = { 'Abseil Team' => 'abseil-io@googlegroups.com' } s.source = { :git => 'https://github.com/abseil/abseil-cpp.git', :tag => '${tag}', } s.resource_bundles = { s.module_name => 'PrivacyInfo.xcprivacy', } s.module_name = 'absl' s.header_mappings_dir = 'absl' s.header_dir = 'absl' s.libraries = 'c++' s.compiler_flags = '-Wno-everything' s.pod_target_xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"', 'USE_HEADERMAP' => 'NO', 'ALWAYS_SEARCH_USER_PATHS' => 'NO', } s.ios.deployment_target = '9.0' s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' s.watchos.deployment_target = '2.0' """ # Rule object representing the rule of Bazel BUILD. Rule = collections.namedtuple( "Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly") def get_elem_value(elem, name): """Returns the value of XML element with the given name.""" for child in elem: if child.attrib.get("name") != name: continue if child.tag == "string": return child.attrib.get("value") if child.tag == "boolean": return child.attrib.get("value") == "true" if child.tag == "list": return [nested_child.attrib.get("value") for nested_child in child] raise "Cannot recognize tag: " + child.tag return None def normalize_paths(paths): """Returns the list of normalized path.""" # e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"] return [path.lstrip("/").replace(":", "/") for path in paths] def parse_rule(elem, package): """Returns a rule from bazel XML rule.""" return Rule( type=elem.attrib["class"], name=get_elem_value(elem, "name"), package=package, srcs=normalize_paths(get_elem_value(elem, "srcs") or []), hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []), textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []), deps=get_elem_value(elem, "deps") or [], visibility=get_elem_value(elem, "visibility") or [], testonly=get_elem_value(elem, "testonly") or False) def read_build(package): """Runs bazel query on given package file and returns all cc rules.""" result = subprocess.check_output( ["bazel", "query", package + ":all", "--output", "xml"]) root = xml.etree.ElementTree.fromstring(result) return [ parse_rule(elem, package) for elem in root if elem.tag == "rule" and elem.attrib["class"].startswith("cc_") ] def collect_rules(root_path): """Collects and returns all rules from root path recursively.""" rules = [] for cur, _, _ in os.walk(root_path): build_path = os.path.join(cur, "BUILD.bazel") if os.path.exists(build_path): rules.extend(read_build("//" + cur)) return rules def relevant_rule(rule): """Returns true if a given rule is relevant when generating a podspec.""" return ( # cc_library only (ignore cc_test, cc_binary) rule.type == "cc_library" and # ignore empty rule (rule.hdrs + rule.textual_hdrs + rule.srcs) and # ignore test-only rule not rule.testonly) def get_spec_var(depth): """Returns the name of variable for spec with given depth.""" return "s" if depth == 0 else "s{}".format(depth) def get_spec_name(label): """Converts the label of bazel rule to the name of podspec.""" assert label.startswith("//absl/"), "{} doesn't start with //absl/".format( label) # e.g. //absl/apple/banana -> abseil/apple/banana return "abseil/" + label[7:] def write_podspec(f, rules, args): """Writes a podspec from given rules and args.""" rule_dir = build_rule_directory(rules)["abseil"] # Write root part with given arguments spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)], SPEC_TEMPLATE).lstrip() f.write(spec) # Write all target rules write_podspec_map(f, rule_dir, 0) f.write("end\n") def build_rule_directory(rules): """Builds a tree-style rule directory from given rules.""" rule_dir = {} for rule in rules: cur = rule_dir for frag in get_spec_name(rule.package).split("/"): cur = cur.setdefault(frag, {}) cur[rule.name] = rule return rule_dir def write_podspec_map(f, cur_map, depth): """Writes podspec from rule map recursively.""" for key, value in sorted(cur_map.items()): indent = " " * (depth + 1) f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format( indent=indent, key=key, var0=get_spec_var(depth), var1=get_spec_var(depth + 1))) if isinstance(value, dict): write_podspec_map(f, value, depth + 1) else: write_podspec_rule(f, value, depth + 1) f.write("{indent}end\n".format(indent=indent)) def write_podspec_rule(f, rule, depth): """Writes podspec from given rule.""" indent = " " * (depth + 1) spec_var = get_spec_var(depth) # Puts all files in hdrs, textual_hdrs, and srcs into source_files. # Since CocoaPods treats header_files a bit differently from bazel, # this won't generate a header_files field so that all source_files # are considered as header files. srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs)) write_indented_list( f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var), srcs) # Writes dependencies of this rule. for dep in sorted(rule.deps): name = get_spec_name(dep.replace(":", "/")) f.write("{indent}{var}.dependency '{dep}'\n".format( indent=indent, var=spec_var, dep=name)) def write_indented_list(f, leading, values): """Writes leading values in an indented style.""" f.write(leading) f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values)) f.write("\n") def generate(args): """Generates a podspec file from all BUILD files under absl directory.""" rules = filter(relevant_rule, collect_rules("absl")) with open(args.output, "wt") as f: write_podspec(f, rules, vars(args)) def main(): parser = argparse.ArgumentParser( description="Generates abseil.podspec from BUILD.bazel") parser.add_argument( "-v", "--version", help="The version of podspec", required=True) parser.add_argument( "-t", "--tag", default=None, help="The name of git tag (default: version)") parser.add_argument( "-o", "--output", default="abseil.podspec", help="The name of output file (default: abseil.podspec)") args = parser.parse_args() if args.tag is None: args.tag = args.version generate(args) if __name__ == "__main__": main() s2/tools/vendor/abseil-cpp/absl/cleanup/0000755000175000017510000000000014737212474017770 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/cleanup/cleanup.h0000644000175000017510000001104214737212474021566 0ustar nileshnilesh// Copyright 2021 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: cleanup.h // ----------------------------------------------------------------------------- // // `absl::Cleanup` implements the scope guard idiom, invoking the contained // callback's `operator()() &&` on scope exit. // // Example: // // ``` // absl::Status CopyGoodData(const char* source_path, const char* sink_path) { // FILE* source_file = fopen(source_path, "r"); // if (source_file == nullptr) { // return absl::NotFoundError("No source file"); // No cleanups execute // } // // // C++17 style cleanup using class template argument deduction // absl::Cleanup source_closer = [source_file] { fclose(source_file); }; // // FILE* sink_file = fopen(sink_path, "w"); // if (sink_file == nullptr) { // return absl::NotFoundError("No sink file"); // First cleanup executes // } // // // C++11 style cleanup using the factory function // auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); }); // // Data data; // while (ReadData(source_file, &data)) { // if (!data.IsGood()) { // absl::Status result = absl::FailedPreconditionError("Read bad data"); // return result; // Both cleanups execute // } // SaveData(sink_file, &data); // } // // return absl::OkStatus(); // Both cleanups execute // } // ``` // // Methods: // // `std::move(cleanup).Cancel()` will prevent the callback from executing. // // `std::move(cleanup).Invoke()` will execute the callback early, before // destruction, and prevent the callback from executing in the destructor. // // Usage: // // `absl::Cleanup` is not an interface type. It is only intended to be used // within the body of a function. It is not a value type and instead models a // control flow construct. Check out `defer` in Golang for something similar. #ifndef ABSL_CLEANUP_CLEANUP_H_ #define ABSL_CLEANUP_CLEANUP_H_ #include #include "absl/base/config.h" #include "absl/base/macros.h" #include "absl/cleanup/internal/cleanup.h" namespace absl { ABSL_NAMESPACE_BEGIN template class ABSL_MUST_USE_RESULT Cleanup final { static_assert(cleanup_internal::WasDeduced(), "Explicit template parameters are not supported."); static_assert(cleanup_internal::ReturnsVoid(), "Callbacks that return values are not supported."); public: Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT Cleanup(Cleanup&& other) = default; void Cancel() && { ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); storage_.DestroyCallback(); } void Invoke() && { ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged()); storage_.InvokeCallback(); storage_.DestroyCallback(); } ~Cleanup() { if (storage_.IsCallbackEngaged()) { storage_.InvokeCallback(); storage_.DestroyCallback(); } } private: cleanup_internal::Storage storage_; }; // `absl::Cleanup c = /* callback */;` // // C++17 type deduction API for creating an instance of `absl::Cleanup` #if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) template Cleanup(Callback callback) -> Cleanup; #endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION) // `auto c = absl::MakeCleanup(/* callback */);` // // C++11 type deduction API for creating an instance of `absl::Cleanup` template absl::Cleanup MakeCleanup(Callback callback) { static_assert(cleanup_internal::WasDeduced(), "Explicit template parameters are not supported."); static_assert(cleanup_internal::ReturnsVoid(), "Callbacks that return values are not supported."); return {std::move(callback)}; } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CLEANUP_CLEANUP_H_ s2/tools/vendor/abseil-cpp/absl/cleanup/BUILD.bazel0000644000175000017510000000310014737212474021640 0ustar nileshnilesh# Copyright 2021 The Abseil Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) package(default_visibility = ["//visibility:public"]) licenses(["notice"]) cc_library( name = "cleanup_internal", hdrs = ["internal/cleanup.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:base_internal", "//absl/base:core_headers", "//absl/utility", ], ) cc_library( name = "cleanup", hdrs = [ "cleanup.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cleanup_internal", "//absl/base:config", "//absl/base:core_headers", ], ) cc_test( name = "cleanup_test", size = "small", srcs = [ "cleanup_test.cc", ], copts = ABSL_TEST_COPTS, deps = [ ":cleanup", "//absl/base:config", "//absl/utility", "@com_google_googletest//:gtest_main", ], ) s2/tools/vendor/abseil-cpp/absl/cleanup/internal/0000755000175000017510000000000014737212474021604 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/cleanup/internal/cleanup.h0000644000175000017510000000531314737212474023406 0ustar nileshnilesh// Copyright 2021 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_ #define ABSL_CLEANUP_INTERNAL_CLEANUP_H_ #include #include #include #include "absl/base/internal/invoke.h" #include "absl/base/macros.h" #include "absl/base/thread_annotations.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cleanup_internal { struct Tag {}; template constexpr bool WasDeduced() { return (std::is_same::value) && (sizeof...(Args) == 0); } template constexpr bool ReturnsVoid() { return (std::is_same, void>::value); } template class Storage { public: Storage() = delete; explicit Storage(Callback callback) { // Placement-new into a character buffer is used for eager destruction when // the cleanup is invoked or cancelled. To ensure this optimizes well, the // behavior is implemented locally instead of using an absl::optional. ::new (GetCallbackBuffer()) Callback(std::move(callback)); is_callback_engaged_ = true; } Storage(Storage&& other) { ABSL_HARDENING_ASSERT(other.IsCallbackEngaged()); ::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback())); is_callback_engaged_ = true; other.DestroyCallback(); } Storage(const Storage& other) = delete; Storage& operator=(Storage&& other) = delete; Storage& operator=(const Storage& other) = delete; void* GetCallbackBuffer() { return static_cast(+callback_buffer_); } Callback& GetCallback() { return *reinterpret_cast(GetCallbackBuffer()); } bool IsCallbackEngaged() const { return is_callback_engaged_; } void DestroyCallback() { is_callback_engaged_ = false; GetCallback().~Callback(); } void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS { std::move(GetCallback())(); } private: bool is_callback_engaged_; alignas(Callback) char callback_buffer_[sizeof(Callback)]; }; } // namespace cleanup_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_ s2/tools/vendor/abseil-cpp/absl/cleanup/CMakeLists.txt0000644000175000017510000000225114737212474022530 0ustar nileshnilesh# Copyright 2021 The Abseil Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Internal-only target, do not depend on directly. absl_cc_library( NAME cleanup_internal HDRS "internal/cleanup.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::base_internal absl::core_headers absl::utility PUBLIC ) absl_cc_library( NAME cleanup HDRS "cleanup.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS absl::cleanup_internal absl::config absl::core_headers PUBLIC ) absl_cc_test( NAME cleanup_test SRCS "cleanup_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS absl::cleanup absl::config absl::utility GTest::gmock_main ) s2/tools/vendor/abseil-cpp/absl/strings/0000755000175000017510000000000014737212474020032 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/strings/charconv.h0000644000175000017510000001154514737212474022014 0ustar nileshnilesh// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_CHARCONV_H_ #define ABSL_STRINGS_CHARCONV_H_ #include // NOLINT(build/c++11) #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN // Workalike compatibility version of std::chars_format from C++17. // // This is an bitfield enumerator which can be passed to absl::from_chars to // configure the string-to-float conversion. enum class chars_format { scientific = 1, fixed = 2, hex = 4, general = fixed | scientific, }; // The return result of a string-to-number conversion. // // `ec` will be set to `invalid_argument` if a well-formed number was not found // at the start of the input range, `result_out_of_range` if a well-formed // number was found, but it was out of the representable range of the requested // type, or to std::errc() otherwise. // // If a well-formed number was found, `ptr` is set to one past the sequence of // characters that were successfully parsed. If none was found, `ptr` is set // to the `first` argument to from_chars. struct from_chars_result { const char* ptr; std::errc ec; }; // Workalike compatibility version of std::from_chars from C++17. Currently // this only supports the `double` and `float` types. // // This interface incorporates the proposed resolutions for library issues // DR 3080 and DR 3081. If these are adopted with different wording, // Abseil's behavior will change to match the standard. (The behavior most // likely to change is for DR 3081, which says what `value` will be set to in // the case of overflow and underflow. Code that wants to avoid possible // breaking changes in this area should not depend on `value` when the returned // from_chars_result indicates a range error.) // // Searches the range [first, last) for the longest matching pattern beginning // at `first` that represents a floating point number. If one is found, store // the result in `value`. // // The matching pattern format is almost the same as that of strtod(), except // that (1) C locale is not respected, (2) an initial '+' character in the // input range will never be matched, and (3) leading whitespaces are not // ignored. // // If `fmt` is set, it must be one of the enumerator values of the chars_format. // (This is despite the fact that chars_format is a bitmask type.) If set to // `scientific`, a matching number must contain an exponent. If set to `fixed`, // then an exponent will never match. (For example, the string "1e5" will be // parsed as "1".) If set to `hex`, then a hexadecimal float is parsed in the // format that strtod() accepts, except that a "0x" prefix is NOT matched. // (In particular, in `hex` mode, the input "0xff" results in the largest // matching pattern "0".) absl::from_chars_result from_chars(const char* first, const char* last, double& value, // NOLINT chars_format fmt = chars_format::general); absl::from_chars_result from_chars(const char* first, const char* last, float& value, // NOLINT chars_format fmt = chars_format::general); // std::chars_format is specified as a bitmask type, which means the following // operations must be provided: inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) { return static_cast(static_cast(lhs) ^ static_cast(rhs)); } inline constexpr chars_format operator~(chars_format arg) { return static_cast(~static_cast(arg)); } inline chars_format& operator&=(chars_format& lhs, chars_format rhs) { lhs = lhs & rhs; return lhs; } inline chars_format& operator|=(chars_format& lhs, chars_format rhs) { lhs = lhs | rhs; return lhs; } inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { lhs = lhs ^ rhs; return lhs; } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CHARCONV_H_ s2/tools/vendor/abseil-cpp/absl/strings/numbers.h0000644000175000017510000003002114737212474021652 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: numbers.h // ----------------------------------------------------------------------------- // // This package contains functions for converting strings to numbers. For // converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h, // which automatically detect and convert most number values appropriately. #ifndef ABSL_STRINGS_NUMBERS_H_ #define ABSL_STRINGS_NUMBERS_H_ #ifdef __SSSE3__ #include #endif #ifdef _MSC_VER #include #endif #include #include #include #include #include #include #include #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/numeric/bits.h" #include "absl/numeric/int128.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // SimpleAtoi() // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into an integer value, returning `true` if successful. The string // must reflect a base-10 integer whose value falls within the range of the // integer type (optionally preceded by a `+` or `-`). If any errors are // encountered, this function returns `false`, leaving `out` in an unspecified // state. template ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out); // SimpleAtof() // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into a float, which may be rounded on overflow or underflow, // returning `true` if successful. // See https://en.cppreference.com/w/c/string/byte/strtof for details about the // allowed formats for `str`, except SimpleAtof() is locale-independent and will // always use the "C" locale. If any errors are encountered, this function // returns `false`, leaving `out` in an unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); // SimpleAtod() // // Converts the given string (optionally followed or preceded by ASCII // whitespace) into a double, which may be rounded on overflow or underflow, // returning `true` if successful. // See https://en.cppreference.com/w/c/string/byte/strtof for details about the // allowed formats for `str`, except SimpleAtod is locale-independent and will // always use the "C" locale. If any errors are encountered, this function // returns `false`, leaving `out` in an unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out); // SimpleAtob() // // Converts the given string into a boolean, returning `true` if successful. // The following case-insensitive strings are interpreted as boolean `true`: // "true", "t", "yes", "y", "1". The following case-insensitive strings // are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any // errors are encountered, this function returns `false`, leaving `out` in an // unspecified state. ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out); // SimpleHexAtoi() // // Converts a hexadecimal string (optionally followed or preceded by ASCII // whitespace) to an integer, returning `true` if successful. Only valid base-16 // hexadecimal integers whose value falls within the range of the integer type // (optionally preceded by a `+` or `-`) can be converted. A valid hexadecimal // value may include both upper and lowercase character symbols, and may // optionally include a leading "0x" (or "0X") number prefix, which is ignored // by this function. If any errors are encountered, this function returns // `false`, leaving `out` in an unspecified state. template ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, int_type* out); // Overloads of SimpleHexAtoi() for 128 bit integers. ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, absl::int128* out); ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, absl::uint128* out); ABSL_NAMESPACE_END } // namespace absl // End of public API. Implementation details follow. namespace absl { ABSL_NAMESPACE_BEGIN namespace numbers_internal { // Digit conversion. ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef ABSL_DLL extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the // range 0 <= i < 100, and buf must have space for two characters. Example: // char buf[2]; // PutTwoDigits(42, buf); // // buf[0] == '4' // // buf[1] == '2' void PutTwoDigits(uint32_t i, char* buf); // safe_strto?() functions for implementing SimpleAtoi() bool safe_strto32_base(absl::string_view text, int32_t* value, int base); bool safe_strto64_base(absl::string_view text, int64_t* value, int base); bool safe_strto128_base(absl::string_view text, absl::int128* value, int base); bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base); bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base); bool safe_strtou128_base(absl::string_view text, absl::uint128* value, int base); static const int kFastToBufferSize = 32; static const int kSixDigitsToBufferSize = 16; // Helper function for fast formatting of floating-point values. // The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six // significant digits are returned, trailing zeros are removed, and numbers // outside the range 0.0001-999999 are output using scientific notation // (1.23456e+06). This routine is heavily optimized. // Required buffer size is `kSixDigitsToBufferSize`. size_t SixDigitsToBuffer(double d, char* buffer); // These functions are intended for speed. All functions take an output buffer // as an argument and return a pointer to the last byte they wrote, which is the // terminating '\0'. At most `kFastToBufferSize` bytes are written. char* FastIntToBuffer(int32_t, char*); char* FastIntToBuffer(uint32_t, char*); char* FastIntToBuffer(int64_t, char*); char* FastIntToBuffer(uint64_t, char*); // For enums and integer types that are not an exact match for the types above, // use templates to call the appropriate one of the four overloads above. template char* FastIntToBuffer(int_type i, char* buffer) { static_assert(sizeof(i) <= 64 / 8, "FastIntToBuffer works only with 64-bit-or-less integers."); // TODO(jorg): This signed-ness check is used because it works correctly // with enums, and it also serves to check that int_type is not a pointer. // If one day something like std::is_signed works, switch to it. // These conditions are constexpr bools to suppress MSVC warning C4127. constexpr bool kIsSigned = static_cast(1) - 2 < 0; constexpr bool kUse64Bit = sizeof(i) > 32 / 8; if (kIsSigned) { if (kUse64Bit) { return FastIntToBuffer(static_cast(i), buffer); } else { return FastIntToBuffer(static_cast(i), buffer); } } else { if (kUse64Bit) { return FastIntToBuffer(static_cast(i), buffer); } else { return FastIntToBuffer(static_cast(i), buffer); } } } // Implementation of SimpleAtoi, generalized to support arbitrary base (used // with base different from 10 elsewhere in Abseil implementation). template ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, int base) { static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, "SimpleAtoi works only with 32-bit or 64-bit integers."); static_assert(!std::is_floating_point::value, "Use SimpleAtof or SimpleAtod instead."); bool parsed; // TODO(jorg): This signed-ness check is used because it works correctly // with enums, and it also serves to check that int_type is not a pointer. // If one day something like std::is_signed works, switch to it. // These conditions are constexpr bools to suppress MSVC warning C4127. constexpr bool kIsSigned = static_cast(1) - 2 < 0; constexpr bool kUse64Bit = sizeof(*out) == 64 / 8; if (kIsSigned) { if (kUse64Bit) { int64_t val; parsed = numbers_internal::safe_strto64_base(s, &val, base); *out = static_cast(val); } else { int32_t val; parsed = numbers_internal::safe_strto32_base(s, &val, base); *out = static_cast(val); } } else { if (kUse64Bit) { uint64_t val; parsed = numbers_internal::safe_strtou64_base(s, &val, base); *out = static_cast(val); } else { uint32_t val; parsed = numbers_internal::safe_strtou32_base(s, &val, base); *out = static_cast(val); } } return parsed; } // FastHexToBufferZeroPad16() // // Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but // without the terminating null character. Thus `out` must be of length >= 16. // Returns the number of non-pad digits of the output (it can never be zero // since 0 has one digit). inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { #ifdef ABSL_INTERNAL_HAVE_SSSE3 uint64_t be = absl::big_endian::FromHost64(val); const auto kNibbleMask = _mm_set1_epi8(0xf); const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); // load lo dword auto v4 = _mm_srli_epi64(v, 4); // shift 4 right auto il = _mm_unpacklo_epi8(v4, v); // interleave bytes auto m = _mm_and_si128(il, kNibbleMask); // mask out nibbles auto hexchars = _mm_shuffle_epi8(kHexDigits, m); // hex chars _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars); #else for (int i = 0; i < 8; ++i) { auto byte = (val >> (56 - 8 * i)) & 0xFF; auto* hex = &absl::numbers_internal::kHexTable[byte * 2]; std::memcpy(out + 2 * i, hex, 2); } #endif // | 0x1 so that even 0 has 1 digit. return 16 - static_cast(countl_zero(val | 0x1) / 4); } } // namespace numbers_internal template ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) { return numbers_internal::safe_strtoi_base(str, out, 10); } ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, absl::int128* out) { return numbers_internal::safe_strto128_base(str, out, 10); } ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str, absl::uint128* out) { return numbers_internal::safe_strtou128_base(str, out, 10); } template ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str, int_type* out) { return numbers_internal::safe_strtoi_base(str, out, 16); } ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, absl::int128* out) { return numbers_internal::safe_strto128_base(str, out, 16); } ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, absl::uint128* out) { return numbers_internal::safe_strtou128_base(str, out, 16); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_NUMBERS_H_ s2/tools/vendor/abseil-cpp/absl/strings/str_join.h0000644000175000017510000002571114737212474022040 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: str_join.h // ----------------------------------------------------------------------------- // // This header file contains functions for joining a range of elements and // returning the result as a std::string. StrJoin operations are specified by // passing a range, a separator string to use between the elements joined, and // an optional Formatter responsible for converting each argument in the range // to a string. If omitted, a default `AlphaNumFormatter()` is called on the // elements to be joined, using the same formatting that `absl::StrCat()` uses. // This package defines a number of default formatters, and you can define your // own implementations. // // Ranges are specified by passing a container with `std::begin()` and // `std::end()` iterators, container-specific `begin()` and `end()` iterators, a // brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous // objects. The separator string is specified as an `absl::string_view`. // // Because the default formatter uses the `absl::AlphaNum` class, // `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on // collections of strings, ints, floats, doubles, etc. // // Example: // // std::vector v = {"foo", "bar", "baz"}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // See comments on the `absl::StrJoin()` function for more examples. #ifndef ABSL_STRINGS_STR_JOIN_H_ #define ABSL_STRINGS_STR_JOIN_H_ #include #include #include #include #include #include #include #include #include "absl/base/macros.h" #include "absl/strings/internal/str_join_internal.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // ----------------------------------------------------------------------------- // Concept: Formatter // ----------------------------------------------------------------------------- // // A Formatter is a function object that is responsible for formatting its // argument as a string and appending it to a given output std::string. // Formatters may be implemented as function objects, lambdas, or normal // functions. You may provide your own Formatter to enable `absl::StrJoin()` to // work with arbitrary types. // // The following is an example of a custom Formatter that uses // `absl::FormatDuration` to join a list of `absl::Duration`s. // // std::vector v = {absl::Seconds(1), absl::Milliseconds(10)}; // std::string s = // absl::StrJoin(v, ", ", [](std::string* out, absl::Duration dur) { // absl::StrAppend(out, absl::FormatDuration(dur)); // }); // EXPECT_EQ("1s, 10ms", s); // // The following standard formatters are provided within this file: // // - `AlphaNumFormatter()` (the default) // - `StreamFormatter()` // - `PairFormatter()` // - `DereferenceFormatter()` // AlphaNumFormatter() // // Default formatter used if none is specified. Uses `absl::AlphaNum` to convert // numeric arguments to strings. inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { return strings_internal::AlphaNumFormatterImpl(); } // StreamFormatter() // // Formats its argument using the << operator. inline strings_internal::StreamFormatterImpl StreamFormatter() { return strings_internal::StreamFormatterImpl(); } // Function Template: PairFormatter(Formatter, absl::string_view, Formatter) // // Formats a `std::pair` by putting a given separator between the pair's // `.first` and `.second` members. This formatter allows you to specify // custom Formatters for both the first and second member of each pair. template inline strings_internal::PairFormatterImpl PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) { return strings_internal::PairFormatterImpl( std::move(f1), sep, std::move(f2)); } // Function overload of PairFormatter() for using a default // `AlphaNumFormatter()` for each Formatter in the pair. inline strings_internal::PairFormatterImpl< strings_internal::AlphaNumFormatterImpl, strings_internal::AlphaNumFormatterImpl> PairFormatter(absl::string_view sep) { return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); } // Function Template: DereferenceFormatter(Formatter) // // Formats its argument by dereferencing it and then applying the given // formatter. This formatter is useful for formatting a container of // pointer-to-T. This pattern often shows up when joining repeated fields in // protocol buffers. template strings_internal::DereferenceFormatterImpl DereferenceFormatter( Formatter&& f) { return strings_internal::DereferenceFormatterImpl( std::forward(f)); } // Function overload of `DereferenceFormatter()` for using a default // `AlphaNumFormatter()`. inline strings_internal::DereferenceFormatterImpl< strings_internal::AlphaNumFormatterImpl> DereferenceFormatter() { return strings_internal::DereferenceFormatterImpl< strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); } // ----------------------------------------------------------------------------- // StrJoin() // ----------------------------------------------------------------------------- // // Joins a range of elements and returns the result as a std::string. // `absl::StrJoin()` takes a range, a separator string to use between the // elements joined, and an optional Formatter responsible for converting each // argument in the range to a string. // // If omitted, the default `AlphaNumFormatter()` is called on the elements to be // joined. // // Example 1: // // Joins a collection of strings. This pattern also works with a collection // // of `absl::string_view` or even `const char*`. // std::vector v = {"foo", "bar", "baz"}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("foo-bar-baz", s); // // Example 2: // // Joins the values in the given `std::initializer_list<>` specified using // // brace initialization. This pattern also works with an initializer_list // // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. // std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); // EXPECT_EQ("foo-bar-baz", s); // // Example 3: // // Joins a collection of ints. This pattern also works with floats, // // doubles, int64s -- any `StrCat()`-compatible type. // std::vector v = {1, 2, 3, -4}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3--4", s); // // Example 4: // // Joins a collection of pointer-to-int. By default, pointers are // // dereferenced and the pointee is formatted using the default format for // // that type; such dereferencing occurs for all levels of indirection, so // // this pattern works just as well for `std::vector` as for // // `std::vector`. // int x = 1, y = 2, z = 3; // std::vector v = {&x, &y, &z}; // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3", s); // // Example 5: // // Dereferencing of `std::unique_ptr<>` is also supported: // std::vector> v // v.emplace_back(new int(1)); // v.emplace_back(new int(2)); // v.emplace_back(new int(3)); // std::string s = absl::StrJoin(v, "-"); // EXPECT_EQ("1-2-3", s); // // Example 6: // // Joins a `std::map`, with each key-value pair separated by an equals // // sign. This pattern would also work with, say, a // // `std::vector>`. // std::map m = { // std::make_pair("a", 1), // std::make_pair("b", 2), // std::make_pair("c", 3)}; // std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); // EXPECT_EQ("a=1,b=2,c=3", s); // // Example 7: // // These examples show how `absl::StrJoin()` handles a few common edge // // cases: // std::vector v_empty; // EXPECT_EQ("", absl::StrJoin(v_empty, "-")); // // std::vector v_one_item = {"foo"}; // EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-")); // // std::vector v_empty_string = {""}; // EXPECT_EQ("", absl::StrJoin(v_empty_string, "-")); // // std::vector v_one_item_empty_string = {"a", ""}; // EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-")); // // std::vector v_two_empty_string = {"", ""}; // EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-")); // // Example 8: // // Joins a `std::tuple` of heterogeneous types, converting each to // // a std::string using the `absl::AlphaNum` class. // std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); // EXPECT_EQ("123-abc-0.456", s); template std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, Formatter&& fmt) { return strings_internal::JoinAlgorithm(start, end, sep, fmt); } template std::string StrJoin(const Range& range, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinRange(range, separator, fmt); } template std::string StrJoin(std::initializer_list il, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinRange(il, separator, fmt); } template std::string StrJoin(const std::tuple& value, absl::string_view separator, Formatter&& fmt) { return strings_internal::JoinAlgorithm(value, separator, fmt); } template std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) { return strings_internal::JoinRange(start, end, separator); } template std::string StrJoin(const Range& range, absl::string_view separator) { return strings_internal::JoinRange(range, separator); } template std::string StrJoin(std::initializer_list il, absl::string_view separator) { return strings_internal::JoinRange(il, separator); } template std::string StrJoin(const std::tuple& value, absl::string_view separator) { return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_JOIN_H_ s2/tools/vendor/abseil-cpp/absl/strings/cord_analysis.h0000644000175000017510000000457214737212474023045 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_CORD_ANALYSIS_H_ #define ABSL_STRINGS_CORD_ANALYSIS_H_ #include #include #include "absl/base/config.h" #include "absl/strings/internal/cord_internal.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // Returns the *approximate* number of bytes held in full or in part by this // Cord (which may not remain the same between invocations). Cords that share // memory could each be "charged" independently for the same shared memory. size_t GetEstimatedMemoryUsage(const CordRep* rep); // Returns the *approximate* number of bytes held in full or in part by this // Cord for the distinct memory held by this cord. This is similar to // `GetEstimatedMemoryUsage()`, except that if the cord has multiple references // to the same memory, that memory is only counted once. // // For example: // absl::Cord cord; // cord.append(some_other_cord); // cord.append(some_other_cord); // // Calls GetEstimatedMemoryUsage() and counts `other_cord` twice: // cord.EstimatedMemoryUsage(kTotal); // // Calls GetMorePreciseMemoryUsage() and counts `other_cord` once: // cord.EstimatedMemoryUsage(kTotalMorePrecise); // // This is more expensive than `GetEstimatedMemoryUsage()` as it requires // deduplicating all memory references. size_t GetMorePreciseMemoryUsage(const CordRep* rep); // Returns the *approximate* number of bytes held in full or in part by this // CordRep weighted by the sharing ratio of that data. For example, if some data // edge is shared by 4 different Cords, then each cord is attribute 1/4th of // the total memory usage as a 'fair share' of the total memory usage. size_t GetEstimatedFairShareMemoryUsage(const CordRep* rep); } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CORD_ANALYSIS_H_ s2/tools/vendor/abseil-cpp/absl/strings/match.h0000644000175000017510000001032014737212474021273 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: match.h // ----------------------------------------------------------------------------- // // This file contains simple utilities for performing string matching checks. // All of these function parameters are specified as `absl::string_view`, // meaning that these functions can accept `std::string`, `absl::string_view` or // NUL-terminated C-style strings. // // Examples: // std::string s = "foo"; // absl::string_view sv = "f"; // assert(absl::StrContains(s, sv)); // // Note: The order of parameters in these functions is designed to mimic the // order an equivalent member function would exhibit; // e.g. `s.Contains(x)` ==> `absl::StrContains(s, x). #ifndef ABSL_STRINGS_MATCH_H_ #define ABSL_STRINGS_MATCH_H_ #include #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // StrContains() // // Returns whether a given string `haystack` contains the substring `needle`. inline bool StrContains(absl::string_view haystack, absl::string_view needle) noexcept { return haystack.find(needle, 0) != haystack.npos; } inline bool StrContains(absl::string_view haystack, char needle) noexcept { return haystack.find(needle) != haystack.npos; } // StartsWith() // // Returns whether a given string `text` begins with `prefix`. inline bool StartsWith(absl::string_view text, absl::string_view prefix) noexcept { return prefix.empty() || (text.size() >= prefix.size() && memcmp(text.data(), prefix.data(), prefix.size()) == 0); } // EndsWith() // // Returns whether a given string `text` ends with `suffix`. inline bool EndsWith(absl::string_view text, absl::string_view suffix) noexcept { return suffix.empty() || (text.size() >= suffix.size() && memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), suffix.size()) == 0); } // StrContainsIgnoreCase() // // Returns whether a given ASCII string `haystack` contains the ASCII substring // `needle`, ignoring case in the comparison. bool StrContainsIgnoreCase(absl::string_view haystack, absl::string_view needle) noexcept; bool StrContainsIgnoreCase(absl::string_view haystack, char needle) noexcept; // EqualsIgnoreCase() // // Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring // case in the comparison. bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) noexcept; // StartsWithIgnoreCase() // // Returns whether a given ASCII string `text` starts with `prefix`, // ignoring case in the comparison. bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) noexcept; // EndsWithIgnoreCase() // // Returns whether a given ASCII string `text` ends with `suffix`, ignoring // case in the comparison. bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) noexcept; // Yields the longest prefix in common between both input strings. // Pointer-wise, the returned result is a subset of input "a". absl::string_view FindLongestCommonPrefix(absl::string_view a, absl::string_view b); // Yields the longest suffix in common between both input strings. // Pointer-wise, the returned result is a subset of input "a". absl::string_view FindLongestCommonSuffix(absl::string_view a, absl::string_view b); ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_MATCH_H_ s2/tools/vendor/abseil-cpp/absl/strings/substitute.cc0000644000175000017510000001266314737212474022564 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/substitute.h" #include #include "absl/base/internal/raw_logging.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace substitute_internal { void SubstituteAndAppendArray(std::string* output, absl::string_view format, const absl::string_view* args_array, size_t num_args) { // Determine total size needed. size_t size = 0; for (size_t i = 0; i < format.size(); i++) { if (format[i] == '$') { if (i + 1 >= format.size()) { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, "Invalid absl::Substitute() format string: \"%s\".", absl::CEscape(format).c_str()); #endif return; } else if (absl::ascii_isdigit( static_cast(format[i + 1]))) { int index = format[i + 1] - '0'; if (static_cast(index) >= num_args) { #ifndef NDEBUG ABSL_RAW_LOG( FATAL, "Invalid absl::Substitute() format string: asked for \"$" "%d\", but only %d args were given. Full format string was: " "\"%s\".", index, static_cast(num_args), absl::CEscape(format).c_str()); #endif return; } size += args_array[index].size(); ++i; // Skip next char. } else if (format[i + 1] == '$') { ++size; ++i; // Skip next char. } else { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, "Invalid absl::Substitute() format string: \"%s\".", absl::CEscape(format).c_str()); #endif return; } } else { ++size; } } if (size == 0) return; // Build the string. size_t original_size = output->size(); strings_internal::STLStringResizeUninitializedAmortized(output, original_size + size); char* target = &(*output)[original_size]; for (size_t i = 0; i < format.size(); i++) { if (format[i] == '$') { if (absl::ascii_isdigit(static_cast(format[i + 1]))) { const absl::string_view src = args_array[format[i + 1] - '0']; target = std::copy(src.begin(), src.end(), target); ++i; // Skip next char. } else if (format[i + 1] == '$') { *target++ = '$'; ++i; // Skip next char. } } else { *target++ = format[i]; } } assert(target == output->data() + output->size()); } Arg::Arg(const void* value) { static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, "fix sizeof(scratch_)"); if (value == nullptr) { piece_ = "NULL"; } else { char* ptr = scratch_ + sizeof(scratch_); uintptr_t num = reinterpret_cast(value); do { *--ptr = absl::numbers_internal::kHexChar[num & 0xf]; num >>= 4; } while (num != 0); *--ptr = 'x'; *--ptr = '0'; piece_ = absl::string_view( ptr, static_cast(scratch_ + sizeof(scratch_) - ptr)); } } // TODO(jorg): Don't duplicate so much code between here and str_cat.cc Arg::Arg(Hex hex) { char* const end = &scratch_[numbers_internal::kFastToBufferSize]; char* writer = end; uint64_t value = hex.value; do { *--writer = absl::numbers_internal::kHexChar[value & 0xF]; value >>= 4; } while (value != 0); char* beg; if (end - writer < hex.width) { beg = end - hex.width; std::fill_n(beg, writer - beg, hex.fill); } else { beg = writer; } piece_ = absl::string_view(beg, static_cast(end - beg)); } // TODO(jorg): Don't duplicate so much code between here and str_cat.cc Arg::Arg(Dec dec) { assert(dec.width <= numbers_internal::kFastToBufferSize); char* const end = &scratch_[numbers_internal::kFastToBufferSize]; char* const minfill = end - dec.width; char* writer = end; uint64_t value = dec.value; bool neg = dec.neg; while (value > 9) { *--writer = '0' + (value % 10); value /= 10; } *--writer = '0' + static_cast(value); if (neg) *--writer = '-'; ptrdiff_t fillers = writer - minfill; if (fillers > 0) { // Tricky: if the fill character is ' ', then it's <+/-> // But...: if the fill character is '0', then it's <+/-> bool add_sign_again = false; if (neg && dec.fill == '0') { // If filling with '0', ++writer; // ignore the sign we just added add_sign_again = true; // and re-add the sign later. } writer -= fillers; std::fill_n(writer, fillers, dec.fill); if (add_sign_again) *--writer = '-'; } piece_ = absl::string_view(writer, static_cast(end - writer)); } } // namespace substitute_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/cord_analysis.cc0000644000175000017510000001517314737212474023202 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/cord_analysis.h" #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/container/inlined_vector.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_ring.h" // #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/functional/function_ref.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { namespace { // Accounting mode for analyzing memory usage. enum class Mode { kFairShare, kTotal, kTotalMorePrecise }; // CordRepRef holds a `const CordRep*` reference in rep, and depending on mode, // holds a 'fraction' representing a cumulative inverse refcount weight. template struct CordRepRef { // Instantiates a CordRepRef instance. explicit CordRepRef(const CordRep* r) : rep(r) {} // Creates a child reference holding the provided child. // Overloaded to add cumulative reference count for kFairShare. CordRepRef Child(const CordRep* child) const { return CordRepRef(child); } const CordRep* rep; }; // RawUsage holds the computed total number of bytes. template struct RawUsage { size_t total = 0; // Add 'size' to total, ignoring the CordRepRef argument. void Add(size_t size, CordRepRef) { total += size; } }; // Overloaded representation of RawUsage that tracks the set of objects // counted, and avoids double-counting objects referenced more than once // by the same Cord. template <> struct RawUsage { size_t total = 0; // TODO(b/289250880): Replace this with a flat_hash_set. std::unordered_set counted; void Add(size_t size, CordRepRef repref) { if (counted.find(repref.rep) == counted.end()) { counted.insert(repref.rep); total += size; } } }; // Returns n / refcount avoiding a div for the common refcount == 1. template double MaybeDiv(double d, refcount_t refcount) { return refcount == 1 ? d : d / refcount; } // Overloaded 'kFairShare' specialization for CordRepRef. This class holds a // `fraction` value which represents a cumulative inverse refcount weight. // For example, a top node with a reference count of 2 will have a fraction // value of 1/2 = 0.5, representing the 'fair share' of memory it references. // A node below such a node with a reference count of 5 then has a fraction of // 0.5 / 5 = 0.1 representing the fair share of memory below that node, etc. template <> struct CordRepRef { // Creates a CordRepRef with the provided rep and top (parent) fraction. explicit CordRepRef(const CordRep* r, double frac = 1.0) : rep(r), fraction(MaybeDiv(frac, r->refcount.Get())) {} // Returns a CordRepRef with a fraction of `this->fraction / child.refcount` CordRepRef Child(const CordRep* child) const { return CordRepRef(child, fraction); } const CordRep* rep; double fraction; }; // Overloaded 'kFairShare' specialization for RawUsage template <> struct RawUsage { double total = 0; // Adds `size` multiplied by `rep.fraction` to the total size. void Add(size_t size, CordRepRef rep) { total += static_cast(size) * rep.fraction; } }; // Computes the estimated memory size of the provided data edge. // External reps are assumed 'heap allocated at their exact size'. template void AnalyzeDataEdge(CordRepRef rep, RawUsage& raw_usage) { assert(IsDataEdge(rep.rep)); // Consume all substrings if (rep.rep->tag == SUBSTRING) { raw_usage.Add(sizeof(CordRepSubstring), rep); rep = rep.Child(rep.rep->substring()->child); } // Consume FLAT / EXTERNAL const size_t size = rep.rep->tag >= FLAT ? rep.rep->flat()->AllocatedSize() : rep.rep->length + sizeof(CordRepExternalImpl); raw_usage.Add(size, rep); } // Computes the memory size of the provided Ring tree. template void AnalyzeRing(CordRepRef rep, RawUsage& raw_usage) { const CordRepRing* ring = rep.rep->ring(); raw_usage.Add(CordRepRing::AllocSize(ring->capacity()), rep); ring->ForEach([&](CordRepRing::index_type pos) { AnalyzeDataEdge(rep.Child(ring->entry_child(pos)), raw_usage); }); } // Computes the memory size of the provided Btree tree. template void AnalyzeBtree(CordRepRef rep, RawUsage& raw_usage) { raw_usage.Add(sizeof(CordRepBtree), rep); const CordRepBtree* tree = rep.rep->btree(); if (tree->height() > 0) { for (CordRep* edge : tree->Edges()) { AnalyzeBtree(rep.Child(edge), raw_usage); } } else { for (CordRep* edge : tree->Edges()) { AnalyzeDataEdge(rep.Child(edge), raw_usage); } } } template size_t GetEstimatedUsage(const CordRep* rep) { // Zero initialized memory usage totals. RawUsage raw_usage; // Capture top level node and refcount into a CordRepRef. CordRepRef repref(rep); // Consume the top level CRC node if present. if (repref.rep->tag == CRC) { raw_usage.Add(sizeof(CordRepCrc), repref); repref = repref.Child(repref.rep->crc()->child); } if (IsDataEdge(repref.rep)) { AnalyzeDataEdge(repref, raw_usage); } else if (repref.rep->tag == BTREE) { AnalyzeBtree(repref, raw_usage); } else if (repref.rep->tag == RING) { AnalyzeRing(repref, raw_usage); } else { assert(false); } return static_cast(raw_usage.total); } } // namespace size_t GetEstimatedMemoryUsage(const CordRep* rep) { return GetEstimatedUsage(rep); } size_t GetEstimatedFairShareMemoryUsage(const CordRep* rep) { return GetEstimatedUsage(rep); } size_t GetMorePreciseMemoryUsage(const CordRep* rep) { return GetEstimatedUsage(rep); } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/str_split.cc0000644000175000017510000001106314737212474022365 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/str_split.h" #include #include #include #include #include #include #include #include #include "absl/base/internal/raw_logging.h" #include "absl/strings/ascii.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { // This GenericFind() template function encapsulates the finding algorithm // shared between the ByString and ByAnyChar delimiters. The FindPolicy // template parameter allows each delimiter to customize the actual find // function to use and the length of the found delimiter. For example, the // Literal delimiter will ultimately use absl::string_view::find(), and the // AnyOf delimiter will use absl::string_view::find_first_of(). template absl::string_view GenericFind(absl::string_view text, absl::string_view delimiter, size_t pos, FindPolicy find_policy) { if (delimiter.empty() && text.length() > 0) { // Special case for empty string delimiters: always return a zero-length // absl::string_view referring to the item at position 1 past pos. return absl::string_view(text.data() + pos + 1, 0); } size_t found_pos = absl::string_view::npos; absl::string_view found(text.data() + text.size(), 0); // By default, not found found_pos = find_policy.Find(text, delimiter, pos); if (found_pos != absl::string_view::npos) { found = absl::string_view(text.data() + found_pos, find_policy.Length(delimiter)); } return found; } // Finds using absl::string_view::find(), therefore the length of the found // delimiter is delimiter.length(). struct LiteralPolicy { static size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) { return text.find(delimiter, pos); } static size_t Length(absl::string_view delimiter) { return delimiter.length(); } }; // Finds using absl::string_view::find_first_of(), therefore the length of the // found delimiter is 1. struct AnyOfPolicy { static size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) { return text.find_first_of(delimiter, pos); } static size_t Length(absl::string_view /* delimiter */) { return 1; } }; } // namespace // // ByString // ByString::ByString(absl::string_view sp) : delimiter_(sp) {} absl::string_view ByString::Find(absl::string_view text, size_t pos) const { if (delimiter_.length() == 1) { // Much faster to call find on a single character than on an // absl::string_view. size_t found_pos = text.find(delimiter_[0], pos); if (found_pos == absl::string_view::npos) return absl::string_view(text.data() + text.size(), 0); return text.substr(found_pos, 1); } return GenericFind(text, delimiter_, pos, LiteralPolicy()); } // // ByChar // absl::string_view ByChar::Find(absl::string_view text, size_t pos) const { size_t found_pos = text.find(c_, pos); if (found_pos == absl::string_view::npos) return absl::string_view(text.data() + text.size(), 0); return text.substr(found_pos, 1); } // // ByAnyChar // ByAnyChar::ByAnyChar(absl::string_view sp) : delimiters_(sp) {} absl::string_view ByAnyChar::Find(absl::string_view text, size_t pos) const { return GenericFind(text, delimiters_, pos, AnyOfPolicy()); } // // ByLength // ByLength::ByLength(ptrdiff_t length) : length_(length) { ABSL_RAW_CHECK(length > 0, ""); } absl::string_view ByLength::Find(absl::string_view text, size_t pos) const { pos = std::min(pos, text.size()); // truncate `pos` absl::string_view substr = text.substr(pos); // If the string is shorter than the chunk size we say we // "can't find the delimiter" so this will be the last chunk. if (substr.length() <= static_cast(length_)) return absl::string_view(text.data() + text.size(), 0); return absl::string_view(substr.data() + length_, 0); } ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/strip.h0000644000175000017510000000611214737212474021344 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: strip.h // ----------------------------------------------------------------------------- // // This file contains various functions for stripping substrings from a string. #ifndef ABSL_STRINGS_STRIP_H_ #define ABSL_STRINGS_STRIP_H_ #include #include #include "absl/base/macros.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // ConsumePrefix() // // Strips the `expected` prefix, if found, from the start of `str`. // If the operation succeeded, `true` is returned. If not, `false` // is returned and `str` is not modified. // // Example: // // absl::string_view input("abc"); // EXPECT_TRUE(absl::ConsumePrefix(&input, "a")); // EXPECT_EQ(input, "bc"); inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) { if (!absl::StartsWith(*str, expected)) return false; str->remove_prefix(expected.size()); return true; } // ConsumeSuffix() // // Strips the `expected` suffix, if found, from the end of `str`. // If the operation succeeded, `true` is returned. If not, `false` // is returned and `str` is not modified. // // Example: // // absl::string_view input("abcdef"); // EXPECT_TRUE(absl::ConsumeSuffix(&input, "def")); // EXPECT_EQ(input, "abc"); inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) { if (!absl::EndsWith(*str, expected)) return false; str->remove_suffix(expected.size()); return true; } // StripPrefix() // // Returns a view into the input string `str` with the given `prefix` removed, // but leaving the original string intact. If the prefix does not match at the // start of the string, returns the original string instead. ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix( absl::string_view str, absl::string_view prefix) { if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size()); return str; } // StripSuffix() // // Returns a view into the input string `str` with the given `suffix` removed, // but leaving the original string intact. If the suffix does not match at the // end of the string, returns the original string instead. ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix( absl::string_view str, absl::string_view suffix) { if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size()); return str; } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STRIP_H_ s2/tools/vendor/abseil-cpp/absl/strings/string_view.h0000644000175000017510000006441714737212474022557 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: string_view.h // ----------------------------------------------------------------------------- // // This file contains the definition of the `absl::string_view` class. A // `string_view` points to a contiguous span of characters, often part or all of // another `std::string`, double-quoted string literal, character array, or even // another `string_view`. // // This `absl::string_view` abstraction is designed to be a drop-in // replacement for the C++17 `std::string_view` abstraction. #ifndef ABSL_STRINGS_STRING_VIEW_H_ #define ABSL_STRINGS_STRING_VIEW_H_ #include #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/throw_delegate.h" #include "absl/base/macros.h" #include "absl/base/optimization.h" #include "absl/base/port.h" #ifdef ABSL_USES_STD_STRING_VIEW #include // IWYU pragma: export namespace absl { ABSL_NAMESPACE_BEGIN using string_view = std::string_view; ABSL_NAMESPACE_END } // namespace absl #else // ABSL_USES_STD_STRING_VIEW #if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \ (defined(__GNUC__) && !defined(__clang__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1928) #define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp #else // ABSL_HAVE_BUILTIN(__builtin_memcmp) #define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp #endif // ABSL_HAVE_BUILTIN(__builtin_memcmp) namespace absl { ABSL_NAMESPACE_BEGIN // absl::string_view // // A `string_view` provides a lightweight view into the string data provided by // a `std::string`, double-quoted string literal, character array, or even // another `string_view`. A `string_view` does *not* own the string to which it // points, and that data cannot be modified through the view. // // You can use `string_view` as a function or method parameter anywhere a // parameter can receive a double-quoted string literal, `const char*`, // `std::string`, or another `absl::string_view` argument with no need to copy // the string data. Systematic use of `string_view` within function arguments // reduces data copies and `strlen()` calls. // // Because of its small size, prefer passing `string_view` by value: // // void MyFunction(absl::string_view arg); // // If circumstances require, you may also pass one by const reference: // // void MyFunction(const absl::string_view& arg); // not preferred // // Passing by value generates slightly smaller code for many architectures. // // In either case, the source data of the `string_view` must outlive the // `string_view` itself. // // A `string_view` is also suitable for local variables if you know that the // lifetime of the underlying object is longer than the lifetime of your // `string_view` variable. However, beware of binding a `string_view` to a // temporary value: // // // BAD use of string_view: lifetime problem // absl::string_view sv = obj.ReturnAString(); // // // GOOD use of string_view: str outlives sv // std::string str = obj.ReturnAString(); // absl::string_view sv = str; // // Due to lifetime issues, a `string_view` is sometimes a poor choice for a // return value and usually a poor choice for a data member. If you do use a // `string_view` this way, it is your responsibility to ensure that the object // pointed to by the `string_view` outlives the `string_view`. // // A `string_view` may represent a whole string or just part of a string. For // example, when splitting a string, `std::vector` is a // natural data type for the output. // // For another example, a Cord is a non-contiguous, potentially very // long string-like object. The Cord class has an interface that iteratively // provides string_view objects that point to the successive pieces of a Cord // object. // // When constructed from a source which is NUL-terminated, the `string_view` // itself will not include the NUL-terminator unless a specific size (including // the NUL) is passed to the constructor. As a result, common idioms that work // on NUL-terminated strings do not work on `string_view` objects. If you write // code that scans a `string_view`, you must check its length rather than test // for nul, for example. Note, however, that nuls may still be embedded within // a `string_view` explicitly. // // You may create a null `string_view` in two ways: // // absl::string_view sv; // absl::string_view sv(nullptr, 0); // // For the above, `sv.data() == nullptr`, `sv.length() == 0`, and // `sv.empty() == true`. Also, if you create a `string_view` with a non-null // pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to // signal an undefined value that is different from other `string_view` values // in a similar fashion to how `const char* p1 = nullptr;` is different from // `const char* p2 = "";`. However, in practice, it is not recommended to rely // on this behavior. // // Be careful not to confuse a null `string_view` with an empty one. A null // `string_view` is an empty `string_view`, but some empty `string_view`s are // not null. Prefer checking for emptiness over checking for null. // // There are many ways to create an empty string_view: // // const char* nullcp = nullptr; // // string_view.size() will return 0 in all cases. // absl::string_view(); // absl::string_view(nullcp, 0); // absl::string_view(""); // absl::string_view("", 0); // absl::string_view("abcdef", 0); // absl::string_view("abcdef" + 6, 0); // // All empty `string_view` objects whether null or not, are equal: // // absl::string_view() == absl::string_view("", 0) // absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0) class string_view { public: using traits_type = std::char_traits; using value_type = char; using pointer = char*; using const_pointer = const char*; using reference = char&; using const_reference = const char&; using const_iterator = const char*; using iterator = const_iterator; using const_reverse_iterator = std::reverse_iterator; using reverse_iterator = const_reverse_iterator; using size_type = size_t; using difference_type = std::ptrdiff_t; static constexpr size_type npos = static_cast(-1); // Null `string_view` constructor constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} // Implicit constructors template string_view( // NOLINT(runtime/explicit) const std::basic_string, Allocator>& str ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // This is implemented in terms of `string_view(p, n)` so `str.size()` // doesn't need to be reevaluated after `ptr_` is set. // The length check is also skipped since it is unnecessary and causes // code bloat. : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} // Implicit constructor of a `string_view` from NUL-terminated `str`. When // accepting possibly null strings, use `absl::NullSafeStringView(str)` // instead (see below). // The length check is skipped since it is unnecessary and causes code bloat. constexpr string_view(const char* str) // NOLINT(runtime/explicit) : ptr_(str), length_(str ? StrlenInternal(str) : 0) {} // Implicit constructor of a `string_view` from a `const char*` and length. constexpr string_view(const char* data, size_type len) : ptr_(data), length_(CheckLengthInternal(len)) {} // NOTE: Harmlessly omitted to work around gdb bug. // constexpr string_view(const string_view&) noexcept = default; // string_view& operator=(const string_view&) noexcept = default; // Iterators // string_view::begin() // // Returns an iterator pointing to the first character at the beginning of the // `string_view`, or `end()` if the `string_view` is empty. constexpr const_iterator begin() const noexcept { return ptr_; } // string_view::end() // // Returns an iterator pointing just beyond the last character at the end of // the `string_view`. This iterator acts as a placeholder; attempting to // access it results in undefined behavior. constexpr const_iterator end() const noexcept { return ptr_ + length_; } // string_view::cbegin() // // Returns a const iterator pointing to the first character at the beginning // of the `string_view`, or `end()` if the `string_view` is empty. constexpr const_iterator cbegin() const noexcept { return begin(); } // string_view::cend() // // Returns a const iterator pointing just beyond the last character at the end // of the `string_view`. This pointer acts as a placeholder; attempting to // access its element results in undefined behavior. constexpr const_iterator cend() const noexcept { return end(); } // string_view::rbegin() // // Returns a reverse iterator pointing to the last character at the end of the // `string_view`, or `rend()` if the `string_view` is empty. const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } // string_view::rend() // // Returns a reverse iterator pointing just before the first character at the // beginning of the `string_view`. This pointer acts as a placeholder; // attempting to access its element results in undefined behavior. const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } // string_view::crbegin() // // Returns a const reverse iterator pointing to the last character at the end // of the `string_view`, or `crend()` if the `string_view` is empty. const_reverse_iterator crbegin() const noexcept { return rbegin(); } // string_view::crend() // // Returns a const reverse iterator pointing just before the first character // at the beginning of the `string_view`. This pointer acts as a placeholder; // attempting to access its element results in undefined behavior. const_reverse_iterator crend() const noexcept { return rend(); } // Capacity Utilities // string_view::size() // // Returns the number of characters in the `string_view`. constexpr size_type size() const noexcept { return length_; } // string_view::length() // // Returns the number of characters in the `string_view`. Alias for `size()`. constexpr size_type length() const noexcept { return size(); } // string_view::max_size() // // Returns the maximum number of characters the `string_view` can hold. constexpr size_type max_size() const noexcept { return kMaxSize; } // string_view::empty() // // Checks if the `string_view` is empty (refers to no characters). constexpr bool empty() const noexcept { return length_ == 0; } // string_view::operator[] // // Returns the ith element of the `string_view` using the array operator. // Note that this operator does not perform any bounds checking. constexpr const_reference operator[](size_type i) const { return ABSL_HARDENING_ASSERT(i < size()), ptr_[i]; } // string_view::at() // // Returns the ith element of the `string_view`. Bounds checking is performed, // and an exception of type `std::out_of_range` will be thrown on invalid // access. constexpr const_reference at(size_type i) const { return ABSL_PREDICT_TRUE(i < size()) ? ptr_[i] : ((void)base_internal::ThrowStdOutOfRange( "absl::string_view::at"), ptr_[i]); } // string_view::front() // // Returns the first element of a `string_view`. constexpr const_reference front() const { return ABSL_HARDENING_ASSERT(!empty()), ptr_[0]; } // string_view::back() // // Returns the last element of a `string_view`. constexpr const_reference back() const { return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1]; } // string_view::data() // // Returns a pointer to the underlying character array (which is of course // stored elsewhere). Note that `string_view::data()` may contain embedded nul // characters, but the returned buffer may or may not be NUL-terminated; // therefore, do not pass `data()` to a routine that expects a NUL-terminated // string. constexpr const_pointer data() const noexcept { return ptr_; } // Modifiers // string_view::remove_prefix() // // Removes the first `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. constexpr void remove_prefix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); ptr_ += n; length_ -= n; } // string_view::remove_suffix() // // Removes the last `n` characters from the `string_view`. Note that the // underlying string is not changed, only the view. constexpr void remove_suffix(size_type n) { ABSL_HARDENING_ASSERT(n <= length_); length_ -= n; } // string_view::swap() // // Swaps this `string_view` with another `string_view`. constexpr void swap(string_view& s) noexcept { auto t = *this; *this = s; s = t; } // Explicit conversion operators // Converts to `std::basic_string`. template explicit operator std::basic_string() const { if (!data()) return {}; return std::basic_string(data(), size()); } // string_view::copy() // // Copies the contents of the `string_view` at offset `pos` and length `n` // into `buf`. size_type copy(char* buf, size_type n, size_type pos = 0) const { if (ABSL_PREDICT_FALSE(pos > length_)) { base_internal::ThrowStdOutOfRange("absl::string_view::copy"); } size_type rlen = (std::min)(length_ - pos, n); if (rlen > 0) { const char* start = ptr_ + pos; traits_type::copy(buf, start, rlen); } return rlen; } // string_view::substr() // // Returns a "substring" of the `string_view` (at offset `pos` and length // `n`) as another string_view. This function throws `std::out_of_bounds` if // `pos > size`. // Use absl::ClippedSubstr if you need a truncating substr operation. constexpr string_view substr(size_type pos = 0, size_type n = npos) const { return ABSL_PREDICT_FALSE(pos > length_) ? (base_internal::ThrowStdOutOfRange( "absl::string_view::substr"), string_view()) : string_view(ptr_ + pos, Min(n, length_ - pos)); } // string_view::compare() // // Performs a lexicographical comparison between this `string_view` and // another `string_view` `x`, returning a negative value if `*this` is less // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` // is greater than `x`. constexpr int compare(string_view x) const noexcept { return CompareImpl(length_, x.length_, Min(length_, x.length_) == 0 ? 0 : ABSL_INTERNAL_STRING_VIEW_MEMCMP( ptr_, x.ptr_, Min(length_, x.length_))); } // Overload of `string_view::compare()` for comparing a substring of the // 'string_view` and another `absl::string_view`. constexpr int compare(size_type pos1, size_type count1, string_view v) const { return substr(pos1, count1).compare(v); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of another `absl::string_view`. constexpr int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const { return substr(pos1, count1).compare(v.substr(pos2, count2)); } // Overload of `string_view::compare()` for comparing a `string_view` and a // a different C-style string `s`. constexpr int compare(const char* s) const { return compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a different string C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s) const { return substr(pos1, count1).compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the // `string_view` and a substring of a different C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s, size_type count2) const { return substr(pos1, count1).compare(string_view(s, count2)); } // Find Utilities // string_view::find() // // Finds the first occurrence of the substring `s` within the `string_view`, // returning the position of the first character's match, or `npos` if no // match was found. size_type find(string_view s, size_type pos = 0) const noexcept; // Overload of `string_view::find()` for finding the given character `c` // within the `string_view`. size_type find(char c, size_type pos = 0) const noexcept; // Overload of `string_view::find()` for finding a substring of a different // C-style string `s` within the `string_view`. size_type find(const char* s, size_type pos, size_type count) const { return find(string_view(s, count), pos); } // Overload of `string_view::find()` for finding a different C-style string // `s` within the `string_view`. size_type find(const char* s, size_type pos = 0) const { return find(string_view(s), pos); } // string_view::rfind() // // Finds the last occurrence of a substring `s` within the `string_view`, // returning the position of the first character's match, or `npos` if no // match was found. size_type rfind(string_view s, size_type pos = npos) const noexcept; // Overload of `string_view::rfind()` for finding the last given character `c` // within the `string_view`. size_type rfind(char c, size_type pos = npos) const noexcept; // Overload of `string_view::rfind()` for finding a substring of a different // C-style string `s` within the `string_view`. size_type rfind(const char* s, size_type pos, size_type count) const { return rfind(string_view(s, count), pos); } // Overload of `string_view::rfind()` for finding a different C-style string // `s` within the `string_view`. size_type rfind(const char* s, size_type pos = npos) const { return rfind(string_view(s), pos); } // string_view::find_first_of() // // Finds the first occurrence of any of the characters in `s` within the // `string_view`, returning the start position of the match, or `npos` if no // match was found. size_type find_first_of(string_view s, size_type pos = 0) const noexcept; // Overload of `string_view::find_first_of()` for finding a character `c` // within the `string_view`. size_type find_first_of(char c, size_type pos = 0) const noexcept { return find(c, pos); } // Overload of `string_view::find_first_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_first_of(const char* s, size_type pos, size_type count) const { return find_first_of(string_view(s, count), pos); } // Overload of `string_view::find_first_of()` for finding a different C-style // string `s` within the `string_view`. size_type find_first_of(const char* s, size_type pos = 0) const { return find_first_of(string_view(s), pos); } // string_view::find_last_of() // // Finds the last occurrence of any of the characters in `s` within the // `string_view`, returning the start position of the match, or `npos` if no // match was found. size_type find_last_of(string_view s, size_type pos = npos) const noexcept; // Overload of `string_view::find_last_of()` for finding a character `c` // within the `string_view`. size_type find_last_of(char c, size_type pos = npos) const noexcept { return rfind(c, pos); } // Overload of `string_view::find_last_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_last_of(const char* s, size_type pos, size_type count) const { return find_last_of(string_view(s, count), pos); } // Overload of `string_view::find_last_of()` for finding a different C-style // string `s` within the `string_view`. size_type find_last_of(const char* s, size_type pos = npos) const { return find_last_of(string_view(s), pos); } // string_view::find_first_not_of() // // Finds the first occurrence of any of the characters not in `s` within the // `string_view`, returning the start position of the first non-match, or // `npos` if no non-match was found. size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; // Overload of `string_view::find_first_not_of()` for finding a character // that is not `c` within the `string_view`. size_type find_first_not_of(char c, size_type pos = 0) const noexcept; // Overload of `string_view::find_first_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_first_not_of(const char* s, size_type pos, size_type count) const { return find_first_not_of(string_view(s, count), pos); } // Overload of `string_view::find_first_not_of()` for finding a different // C-style string `s` within the `string_view`. size_type find_first_not_of(const char* s, size_type pos = 0) const { return find_first_not_of(string_view(s), pos); } // string_view::find_last_not_of() // // Finds the last occurrence of any of the characters not in `s` within the // `string_view`, returning the start position of the last non-match, or // `npos` if no non-match was found. size_type find_last_not_of(string_view s, size_type pos = npos) const noexcept; // Overload of `string_view::find_last_not_of()` for finding a character // that is not `c` within the `string_view`. size_type find_last_not_of(char c, size_type pos = npos) const noexcept; // Overload of `string_view::find_last_not_of()` for finding a substring of a // different C-style string `s` within the `string_view`. size_type find_last_not_of(const char* s, size_type pos, size_type count) const { return find_last_not_of(string_view(s, count), pos); } // Overload of `string_view::find_last_not_of()` for finding a different // C-style string `s` within the `string_view`. size_type find_last_not_of(const char* s, size_type pos = npos) const { return find_last_not_of(string_view(s), pos); } private: // The constructor from std::string delegates to this constructor. // See the comment on that constructor for the rationale. struct SkipCheckLengthTag {}; string_view(const char* data, size_type len, SkipCheckLengthTag) noexcept : ptr_(data), length_(len) {} static constexpr size_type kMaxSize = (std::numeric_limits::max)(); static constexpr size_type CheckLengthInternal(size_type len) { return ABSL_HARDENING_ASSERT(len <= kMaxSize), len; } static constexpr size_type StrlenInternal(const char* str) { #if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__) // MSVC 2017+ can evaluate this at compile-time. const char* begin = str; while (*str != '\0') ++str; return str - begin; #elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \ (defined(__GNUC__) && !defined(__clang__)) // GCC has __builtin_strlen according to // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above. // __builtin_strlen is constexpr. return __builtin_strlen(str); #else return str ? strlen(str) : 0; #endif } static constexpr size_t Min(size_type length_a, size_type length_b) { return length_a < length_b ? length_a : length_b; } static constexpr int CompareImpl(size_type length_a, size_type length_b, int compare_result) { return compare_result == 0 ? static_cast(length_a > length_b) - static_cast(length_a < length_b) : (compare_result < 0 ? -1 : 1); } const char* ptr_; size_type length_; }; // This large function is defined inline so that in a fairly common case where // one of the arguments is a literal, the compiler can elide a lot of the // following comparisons. constexpr bool operator==(string_view x, string_view y) noexcept { return x.size() == y.size() && (x.empty() || ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0); } constexpr bool operator!=(string_view x, string_view y) noexcept { return !(x == y); } constexpr bool operator<(string_view x, string_view y) noexcept { return x.compare(y) < 0; } constexpr bool operator>(string_view x, string_view y) noexcept { return y < x; } constexpr bool operator<=(string_view x, string_view y) noexcept { return !(y < x); } constexpr bool operator>=(string_view x, string_view y) noexcept { return !(x < y); } // IO Insertion Operator std::ostream& operator<<(std::ostream& o, string_view piece); ABSL_NAMESPACE_END } // namespace absl #undef ABSL_INTERNAL_STRING_VIEW_MEMCMP #endif // ABSL_USES_STD_STRING_VIEW namespace absl { ABSL_NAMESPACE_BEGIN // ClippedSubstr() // // Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`. // Provided because std::string_view::substr throws if `pos > size()` inline string_view ClippedSubstr(string_view s, size_t pos, size_t n = string_view::npos) { pos = (std::min)(pos, static_cast(s.size())); return s.substr(pos, n); } // NullSafeStringView() // // Creates an `absl::string_view` from a pointer `p` even if it's null-valued. // This function should be used where an `absl::string_view` can be created from // a possibly-null pointer. constexpr string_view NullSafeStringView(const char* p) { return p ? string_view(p) : string_view(); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STRING_VIEW_H_ s2/tools/vendor/abseil-cpp/absl/strings/cord.cc0000644000175000017510000013157414737212474021303 0ustar nileshnilesh// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/cord.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "absl/base/casts.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/container/fixed_array.h" #include "absl/container/inlined_vector.h" #include "absl/crc/internal/crc_cord_state.h" #include "absl/strings/cord_buffer.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN using ::absl::cord_internal::CordRep; using ::absl::cord_internal::CordRepBtree; using ::absl::cord_internal::CordRepCrc; using ::absl::cord_internal::CordRepExternal; using ::absl::cord_internal::CordRepFlat; using ::absl::cord_internal::CordRepSubstring; using ::absl::cord_internal::CordzUpdateTracker; using ::absl::cord_internal::InlineData; using ::absl::cord_internal::kMaxFlatLength; using ::absl::cord_internal::kMinFlatLength; using ::absl::cord_internal::kInlinedVectorSize; using ::absl::cord_internal::kMaxBytesToCopy; static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, int indent = 0); static bool VerifyNode(CordRep* root, CordRep* start_node, bool full_validation); static inline CordRep* VerifyTree(CordRep* node) { // Verification is expensive, so only do it in debug mode. // Even in debug mode we normally do only light validation. // If you are debugging Cord itself, you should define the // macro EXTRA_CORD_VALIDATION, e.g. by adding // --copt=-DEXTRA_CORD_VALIDATION to the blaze line. #ifdef EXTRA_CORD_VALIDATION assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true)); #else // EXTRA_CORD_VALIDATION assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false)); #endif // EXTRA_CORD_VALIDATION static_cast(&VerifyNode); return node; } static CordRepFlat* CreateFlat(const char* data, size_t length, size_t alloc_hint) { CordRepFlat* flat = CordRepFlat::New(length + alloc_hint); flat->length = length; memcpy(flat->Data(), data, length); return flat; } // Creates a new flat or Btree out of the specified array. // The returned node has a refcount of 1. static CordRep* NewBtree(const char* data, size_t length, size_t alloc_hint) { if (length <= kMaxFlatLength) { return CreateFlat(data, length, alloc_hint); } CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0); data += kMaxFlatLength; length -= kMaxFlatLength; auto* root = CordRepBtree::Create(flat); return CordRepBtree::Append(root, {data, length}, alloc_hint); } // Create a new tree out of the specified array. // The returned node has a refcount of 1. static CordRep* NewTree(const char* data, size_t length, size_t alloc_hint) { if (length == 0) return nullptr; return NewBtree(data, length, alloc_hint); } namespace cord_internal { void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) { assert(!data.empty()); rep->length = data.size(); rep->tag = EXTERNAL; rep->base = data.data(); VerifyTree(rep); } } // namespace cord_internal // Creates a CordRep from the provided string. If the string is large enough, // and not wasteful, we move the string into an external cord rep, preserving // the already allocated string contents. // Requires the provided string length to be larger than `kMaxInline`. static CordRep* CordRepFromString(std::string&& src) { assert(src.length() > cord_internal::kMaxInline); if ( // String is short: copy data to avoid external block overhead. src.size() <= kMaxBytesToCopy || // String is wasteful: copy data to avoid pinning too much unused memory. src.size() < src.capacity() / 2 ) { return NewTree(src.data(), src.size(), 0); } struct StringReleaser { void operator()(absl::string_view /* data */) {} std::string data; }; const absl::string_view original_data = src; auto* rep = static_cast<::absl::cord_internal::CordRepExternalImpl*>( absl::cord_internal::NewExternalRep(original_data, StringReleaser{std::move(src)})); // Moving src may have invalidated its data pointer, so adjust it. rep->base = rep->template get<0>().data.data(); return rep; } // -------------------------------------------------------------------- // Cord::InlineRep functions #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr unsigned char Cord::InlineRep::kMaxInline; #endif inline void Cord::InlineRep::set_data(const char* data, size_t n) { static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15"); data_.set_inline_data(data, n); } inline char* Cord::InlineRep::set_data(size_t n) { assert(n <= kMaxInline); ResetToEmpty(); set_inline_size(n); return data_.as_chars(); } inline void Cord::InlineRep::reduce_size(size_t n) { size_t tag = inline_size(); assert(tag <= kMaxInline); assert(tag >= n); tag -= n; memset(data_.as_chars() + tag, 0, n); set_inline_size(tag); } inline void Cord::InlineRep::remove_prefix(size_t n) { cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n, inline_size() - n); reduce_size(n); } // Returns `rep` converted into a CordRepBtree. // Directly returns `rep` if `rep` is already a CordRepBtree. static CordRepBtree* ForceBtree(CordRep* rep) { return rep->IsBtree() ? rep->btree() : CordRepBtree::Create(cord_internal::RemoveCrcNode(rep)); } void Cord::InlineRep::AppendTreeToInlined(CordRep* tree, MethodIdentifier method) { assert(!is_tree()); if (!data_.is_empty()) { CordRepFlat* flat = MakeFlatWithExtraCapacity(0); tree = CordRepBtree::Append(CordRepBtree::Create(flat), tree); } EmplaceTree(tree, method); } void Cord::InlineRep::AppendTreeToTree(CordRep* tree, MethodIdentifier method) { assert(is_tree()); const CordzUpdateScope scope(data_.cordz_info(), method); tree = CordRepBtree::Append(ForceBtree(data_.as_tree()), tree); SetTree(tree, scope); } void Cord::InlineRep::AppendTree(CordRep* tree, MethodIdentifier method) { assert(tree != nullptr); assert(tree->length != 0); assert(!tree->IsCrc()); if (data_.is_tree()) { AppendTreeToTree(tree, method); } else { AppendTreeToInlined(tree, method); } } void Cord::InlineRep::PrependTreeToInlined(CordRep* tree, MethodIdentifier method) { assert(!is_tree()); if (!data_.is_empty()) { CordRepFlat* flat = MakeFlatWithExtraCapacity(0); tree = CordRepBtree::Prepend(CordRepBtree::Create(flat), tree); } EmplaceTree(tree, method); } void Cord::InlineRep::PrependTreeToTree(CordRep* tree, MethodIdentifier method) { assert(is_tree()); const CordzUpdateScope scope(data_.cordz_info(), method); tree = CordRepBtree::Prepend(ForceBtree(data_.as_tree()), tree); SetTree(tree, scope); } void Cord::InlineRep::PrependTree(CordRep* tree, MethodIdentifier method) { assert(tree != nullptr); assert(tree->length != 0); assert(!tree->IsCrc()); if (data_.is_tree()) { PrependTreeToTree(tree, method); } else { PrependTreeToInlined(tree, method); } } // Searches for a non-full flat node at the rightmost leaf of the tree. If a // suitable leaf is found, the function will update the length field for all // nodes to account for the size increase. The append region address will be // written to region and the actual size increase will be written to size. static inline bool PrepareAppendRegion(CordRep* root, char** region, size_t* size, size_t max_length) { if (root->IsBtree() && root->refcount.IsOne()) { Span span = root->btree()->GetAppendBuffer(max_length); if (!span.empty()) { *region = span.data(); *size = span.size(); return true; } } CordRep* dst = root; if (!dst->IsFlat() || !dst->refcount.IsOne()) { *region = nullptr; *size = 0; return false; } const size_t in_use = dst->length; const size_t capacity = dst->flat()->Capacity(); if (in_use == capacity) { *region = nullptr; *size = 0; return false; } const size_t size_increase = std::min(capacity - in_use, max_length); dst->length += size_increase; *region = dst->flat()->Data() + in_use; *size = size_increase; return true; } void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { assert(&src != this); assert(is_tree() || src.is_tree()); auto constexpr method = CordzUpdateTracker::kAssignCord; if (ABSL_PREDICT_TRUE(!is_tree())) { EmplaceTree(CordRep::Ref(src.as_tree()), src.data_, method); return; } CordRep* tree = as_tree(); if (CordRep* src_tree = src.tree()) { // Leave any existing `cordz_info` in place, and let MaybeTrackCord() // decide if this cord should be (or remains to be) sampled or not. data_.set_tree(CordRep::Ref(src_tree)); CordzInfo::MaybeTrackCord(data_, src.data_, method); } else { CordzInfo::MaybeUntrackCord(data_.cordz_info()); data_ = src.data_; } CordRep::Unref(tree); } void Cord::InlineRep::UnrefTree() { if (is_tree()) { CordzInfo::MaybeUntrackCord(data_.cordz_info()); CordRep::Unref(tree()); } } // -------------------------------------------------------------------- // Constructors and destructors Cord::Cord(absl::string_view src, MethodIdentifier method) : contents_(InlineData::kDefaultInit) { const size_t n = src.size(); if (n <= InlineRep::kMaxInline) { contents_.set_data(src.data(), n); } else { CordRep* rep = NewTree(src.data(), n, 0); contents_.EmplaceTree(rep, method); } } template > Cord::Cord(T&& src) : contents_(InlineData::kDefaultInit) { if (src.size() <= InlineRep::kMaxInline) { contents_.set_data(src.data(), src.size()); } else { CordRep* rep = CordRepFromString(std::forward(src)); contents_.EmplaceTree(rep, CordzUpdateTracker::kConstructorString); } } template Cord::Cord(std::string&& src); // The destruction code is separate so that the compiler can determine // that it does not need to call the destructor on a moved-from Cord. void Cord::DestroyCordSlow() { assert(contents_.is_tree()); CordzInfo::MaybeUntrackCord(contents_.cordz_info()); CordRep::Unref(VerifyTree(contents_.as_tree())); } // -------------------------------------------------------------------- // Mutators void Cord::Clear() { if (CordRep* tree = contents_.clear()) { CordRep::Unref(tree); } } Cord& Cord::AssignLargeString(std::string&& src) { auto constexpr method = CordzUpdateTracker::kAssignString; assert(src.size() > kMaxBytesToCopy); CordRep* rep = CordRepFromString(std::move(src)); if (CordRep* tree = contents_.tree()) { CordzUpdateScope scope(contents_.cordz_info(), method); contents_.SetTree(rep, scope); CordRep::Unref(tree); } else { contents_.EmplaceTree(rep, method); } return *this; } Cord& Cord::operator=(absl::string_view src) { auto constexpr method = CordzUpdateTracker::kAssignString; const char* data = src.data(); size_t length = src.size(); CordRep* tree = contents_.tree(); if (length <= InlineRep::kMaxInline) { // Embed into this->contents_, which is somewhat subtle: // - MaybeUntrackCord must be called before Unref(tree). // - MaybeUntrackCord must be called before set_data() clobbers cordz_info. // - set_data() must be called before Unref(tree) as it may reference tree. if (tree != nullptr) CordzInfo::MaybeUntrackCord(contents_.cordz_info()); contents_.set_data(data, length); if (tree != nullptr) CordRep::Unref(tree); return *this; } if (tree != nullptr) { CordzUpdateScope scope(contents_.cordz_info(), method); if (tree->IsFlat() && tree->flat()->Capacity() >= length && tree->refcount.IsOne()) { // Copy in place if the existing FLAT node is reusable. memmove(tree->flat()->Data(), data, length); tree->length = length; VerifyTree(tree); return *this; } contents_.SetTree(NewTree(data, length, 0), scope); CordRep::Unref(tree); } else { contents_.EmplaceTree(NewTree(data, length, 0), method); } return *this; } // TODO(sanjay): Move to Cord::InlineRep section of file. For now, // we keep it here to make diffs easier. void Cord::InlineRep::AppendArray(absl::string_view src, MethodIdentifier method) { MaybeRemoveEmptyCrcNode(); if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. size_t appended = 0; CordRep* rep = tree(); const CordRep* const root = rep; CordzUpdateScope scope(root ? cordz_info() : nullptr, method); if (root != nullptr) { rep = cord_internal::RemoveCrcNode(rep); char* region; if (PrepareAppendRegion(rep, ®ion, &appended, src.size())) { memcpy(region, src.data(), appended); } } else { // Try to fit in the inline buffer if possible. size_t inline_length = inline_size(); if (src.size() <= kMaxInline - inline_length) { // Append new data to embedded array set_inline_size(inline_length + src.size()); memcpy(data_.as_chars() + inline_length, src.data(), src.size()); return; } // Allocate flat to be a perfect fit on first append exceeding inlined size. // Subsequent growth will use amortized growth until we reach maximum flat // size. rep = CordRepFlat::New(inline_length + src.size()); appended = std::min(src.size(), rep->flat()->Capacity() - inline_length); memcpy(rep->flat()->Data(), data_.as_chars(), inline_length); memcpy(rep->flat()->Data() + inline_length, src.data(), appended); rep->length = inline_length + appended; } src.remove_prefix(appended); if (src.empty()) { CommitTree(root, rep, scope, method); return; } // TODO(b/192061034): keep legacy 10% growth rate: consider other rates. rep = ForceBtree(rep); const size_t min_growth = std::max(rep->length / 10, src.size()); rep = CordRepBtree::Append(rep->btree(), src, min_growth - src.size()); CommitTree(root, rep, scope, method); } inline CordRep* Cord::TakeRep() const& { return CordRep::Ref(contents_.tree()); } inline CordRep* Cord::TakeRep() && { CordRep* rep = contents_.tree(); contents_.clear(); return rep; } template inline void Cord::AppendImpl(C&& src) { auto constexpr method = CordzUpdateTracker::kAppendCord; contents_.MaybeRemoveEmptyCrcNode(); if (src.empty()) return; if (empty()) { // Since destination is empty, we can avoid allocating a node, if (src.contents_.is_tree()) { // by taking the tree directly CordRep* rep = cord_internal::RemoveCrcNode(std::forward(src).TakeRep()); contents_.EmplaceTree(rep, method); } else { // or copying over inline data contents_.data_ = src.contents_.data_; } return; } // For short cords, it is faster to copy data if there is room in dst. const size_t src_size = src.contents_.size(); if (src_size <= kMaxBytesToCopy) { CordRep* src_tree = src.contents_.tree(); if (src_tree == nullptr) { // src has embedded data. contents_.AppendArray({src.contents_.data(), src_size}, method); return; } if (src_tree->IsFlat()) { // src tree just has one flat node. contents_.AppendArray({src_tree->flat()->Data(), src_size}, method); return; } if (&src == this) { // ChunkIterator below assumes that src is not modified during traversal. Append(Cord(src)); return; } // TODO(mec): Should we only do this if "dst" has space? for (absl::string_view chunk : src.Chunks()) { Append(chunk); } return; } // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize) CordRep* rep = cord_internal::RemoveCrcNode(std::forward(src).TakeRep()); contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord); } static CordRep::ExtractResult ExtractAppendBuffer(CordRep* rep, size_t min_capacity) { switch (rep->tag) { case cord_internal::BTREE: return CordRepBtree::ExtractAppendBuffer(rep->btree(), min_capacity); default: if (rep->IsFlat() && rep->refcount.IsOne() && rep->flat()->Capacity() - rep->length >= min_capacity) { return {nullptr, rep}; } return {rep, nullptr}; } } static CordBuffer CreateAppendBuffer(InlineData& data, size_t block_size, size_t capacity) { // Watch out for overflow, people can ask for size_t::max(). const size_t size = data.inline_size(); const size_t max_capacity = std::numeric_limits::max() - size; capacity = (std::min)(max_capacity, capacity) + size; CordBuffer buffer = block_size ? CordBuffer::CreateWithCustomLimit(block_size, capacity) : CordBuffer::CreateWithDefaultLimit(capacity); cord_internal::SmallMemmove(buffer.data(), data.as_chars(), size); buffer.SetLength(size); data = {}; return buffer; } CordBuffer Cord::GetAppendBufferSlowPath(size_t block_size, size_t capacity, size_t min_capacity) { auto constexpr method = CordzUpdateTracker::kGetAppendBuffer; CordRep* tree = contents_.tree(); if (tree != nullptr) { CordzUpdateScope scope(contents_.cordz_info(), method); CordRep::ExtractResult result = ExtractAppendBuffer(tree, min_capacity); if (result.extracted != nullptr) { contents_.SetTreeOrEmpty(result.tree, scope); return CordBuffer(result.extracted->flat()); } return block_size ? CordBuffer::CreateWithCustomLimit(block_size, capacity) : CordBuffer::CreateWithDefaultLimit(capacity); } return CreateAppendBuffer(contents_.data_, block_size, capacity); } void Cord::Append(const Cord& src) { AppendImpl(src); } void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); } template > void Cord::Append(T&& src) { if (src.size() <= kMaxBytesToCopy) { Append(absl::string_view(src)); } else { CordRep* rep = CordRepFromString(std::forward(src)); contents_.AppendTree(rep, CordzUpdateTracker::kAppendString); } } template void Cord::Append(std::string&& src); void Cord::Prepend(const Cord& src) { contents_.MaybeRemoveEmptyCrcNode(); if (src.empty()) return; CordRep* src_tree = src.contents_.tree(); if (src_tree != nullptr) { CordRep::Ref(src_tree); contents_.PrependTree(cord_internal::RemoveCrcNode(src_tree), CordzUpdateTracker::kPrependCord); return; } // `src` cord is inlined. absl::string_view src_contents(src.contents_.data(), src.contents_.size()); return Prepend(src_contents); } void Cord::PrependArray(absl::string_view src, MethodIdentifier method) { contents_.MaybeRemoveEmptyCrcNode(); if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. if (!contents_.is_tree()) { size_t cur_size = contents_.inline_size(); if (cur_size + src.size() <= InlineRep::kMaxInline) { // Use embedded storage. InlineData data; data.set_inline_size(cur_size + src.size()); memcpy(data.as_chars(), src.data(), src.size()); memcpy(data.as_chars() + src.size(), contents_.data(), cur_size); contents_.data_ = data; return; } } CordRep* rep = NewTree(src.data(), src.size(), 0); contents_.PrependTree(rep, method); } void Cord::AppendPrecise(absl::string_view src, MethodIdentifier method) { assert(!src.empty()); assert(src.size() <= cord_internal::kMaxFlatLength); if (contents_.remaining_inline_capacity() >= src.size()) { const size_t inline_length = contents_.inline_size(); contents_.set_inline_size(inline_length + src.size()); memcpy(contents_.data_.as_chars() + inline_length, src.data(), src.size()); } else { contents_.AppendTree(CordRepFlat::Create(src), method); } } void Cord::PrependPrecise(absl::string_view src, MethodIdentifier method) { assert(!src.empty()); assert(src.size() <= cord_internal::kMaxFlatLength); if (contents_.remaining_inline_capacity() >= src.size()) { const size_t cur_size = contents_.inline_size(); InlineData data; data.set_inline_size(cur_size + src.size()); memcpy(data.as_chars(), src.data(), src.size()); memcpy(data.as_chars() + src.size(), contents_.data(), cur_size); contents_.data_ = data; } else { contents_.PrependTree(CordRepFlat::Create(src), method); } } template > inline void Cord::Prepend(T&& src) { if (src.size() <= kMaxBytesToCopy) { Prepend(absl::string_view(src)); } else { CordRep* rep = CordRepFromString(std::forward(src)); contents_.PrependTree(rep, CordzUpdateTracker::kPrependString); } } template void Cord::Prepend(std::string&& src); void Cord::RemovePrefix(size_t n) { ABSL_INTERNAL_CHECK(n <= size(), absl::StrCat("Requested prefix size ", n, " exceeds Cord's size ", size())); contents_.MaybeRemoveEmptyCrcNode(); CordRep* tree = contents_.tree(); if (tree == nullptr) { contents_.remove_prefix(n); } else { auto constexpr method = CordzUpdateTracker::kRemovePrefix; CordzUpdateScope scope(contents_.cordz_info(), method); tree = cord_internal::RemoveCrcNode(tree); if (n >= tree->length) { CordRep::Unref(tree); tree = nullptr; } else if (tree->IsBtree()) { CordRep* old = tree; tree = tree->btree()->SubTree(n, tree->length - n); CordRep::Unref(old); } else if (tree->IsSubstring() && tree->refcount.IsOne()) { tree->substring()->start += n; tree->length -= n; } else { CordRep* rep = CordRepSubstring::Substring(tree, n, tree->length - n); CordRep::Unref(tree); tree = rep; } contents_.SetTreeOrEmpty(tree, scope); } } void Cord::RemoveSuffix(size_t n) { ABSL_INTERNAL_CHECK(n <= size(), absl::StrCat("Requested suffix size ", n, " exceeds Cord's size ", size())); contents_.MaybeRemoveEmptyCrcNode(); CordRep* tree = contents_.tree(); if (tree == nullptr) { contents_.reduce_size(n); } else { auto constexpr method = CordzUpdateTracker::kRemoveSuffix; CordzUpdateScope scope(contents_.cordz_info(), method); tree = cord_internal::RemoveCrcNode(tree); if (n >= tree->length) { CordRep::Unref(tree); tree = nullptr; } else if (tree->IsBtree()) { tree = CordRepBtree::RemoveSuffix(tree->btree(), n); } else if (!tree->IsExternal() && tree->refcount.IsOne()) { assert(tree->IsFlat() || tree->IsSubstring()); tree->length -= n; } else { CordRep* rep = CordRepSubstring::Substring(tree, 0, tree->length - n); CordRep::Unref(tree); tree = rep; } contents_.SetTreeOrEmpty(tree, scope); } } Cord Cord::Subcord(size_t pos, size_t new_size) const { Cord sub_cord; size_t length = size(); if (pos > length) pos = length; if (new_size > length - pos) new_size = length - pos; if (new_size == 0) return sub_cord; CordRep* tree = contents_.tree(); if (tree == nullptr) { sub_cord.contents_.set_data(contents_.data() + pos, new_size); return sub_cord; } if (new_size <= InlineRep::kMaxInline) { sub_cord.contents_.set_inline_size(new_size); char* dest = sub_cord.contents_.data_.as_chars(); Cord::ChunkIterator it = chunk_begin(); it.AdvanceBytes(pos); size_t remaining_size = new_size; while (remaining_size > it->size()) { cord_internal::SmallMemmove(dest, it->data(), it->size()); remaining_size -= it->size(); dest += it->size(); ++it; } cord_internal::SmallMemmove(dest, it->data(), remaining_size); return sub_cord; } tree = cord_internal::SkipCrcNode(tree); if (tree->IsBtree()) { tree = tree->btree()->SubTree(pos, new_size); } else { tree = CordRepSubstring::Substring(tree, pos, new_size); } sub_cord.contents_.EmplaceTree(tree, contents_.data_, CordzUpdateTracker::kSubCord); return sub_cord; } // -------------------------------------------------------------------- // Comparators namespace { int ClampResult(int memcmp_res) { return static_cast(memcmp_res > 0) - static_cast(memcmp_res < 0); } int CompareChunks(absl::string_view* lhs, absl::string_view* rhs, size_t* size_to_compare) { size_t compared_size = std::min(lhs->size(), rhs->size()); assert(*size_to_compare >= compared_size); *size_to_compare -= compared_size; int memcmp_res = ::memcmp(lhs->data(), rhs->data(), compared_size); if (memcmp_res != 0) return memcmp_res; lhs->remove_prefix(compared_size); rhs->remove_prefix(compared_size); return 0; } // This overload set computes comparison results from memcmp result. This // interface is used inside GenericCompare below. Different implementations // are specialized for int and bool. For int we clamp result to {-1, 0, 1} // set. For bool we just interested in "value == 0". template ResultType ComputeCompareResult(int memcmp_res) { return ClampResult(memcmp_res); } template <> bool ComputeCompareResult(int memcmp_res) { return memcmp_res == 0; } } // namespace // Helper routine. Locates the first flat or external chunk of the Cord without // initializing the iterator, and returns a string_view referencing the data. inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const { if (!is_tree()) { return absl::string_view(data_.as_chars(), data_.inline_size()); } CordRep* node = cord_internal::SkipCrcNode(tree()); if (node->IsFlat()) { return absl::string_view(node->flat()->Data(), node->length); } if (node->IsExternal()) { return absl::string_view(node->external()->base, node->length); } if (node->IsBtree()) { CordRepBtree* tree = node->btree(); int height = tree->height(); while (--height >= 0) { tree = tree->Edge(CordRepBtree::kFront)->btree(); } return tree->Data(tree->begin()); } // Get the child node if we encounter a SUBSTRING. size_t offset = 0; size_t length = node->length; assert(length != 0); if (node->IsSubstring()) { offset = node->substring()->start; node = node->substring()->child; } if (node->IsFlat()) { return absl::string_view(node->flat()->Data() + offset, length); } assert(node->IsExternal() && "Expect FLAT or EXTERNAL node here"); return absl::string_view(node->external()->base + offset, length); } void Cord::SetCrcCordState(crc_internal::CrcCordState state) { auto constexpr method = CordzUpdateTracker::kSetExpectedChecksum; if (empty()) { contents_.MaybeRemoveEmptyCrcNode(); CordRep* rep = CordRepCrc::New(nullptr, std::move(state)); contents_.EmplaceTree(rep, method); } else if (!contents_.is_tree()) { CordRep* rep = contents_.MakeFlatWithExtraCapacity(0); rep = CordRepCrc::New(rep, std::move(state)); contents_.EmplaceTree(rep, method); } else { const CordzUpdateScope scope(contents_.data_.cordz_info(), method); CordRep* rep = CordRepCrc::New(contents_.data_.as_tree(), std::move(state)); contents_.SetTree(rep, scope); } } void Cord::SetExpectedChecksum(uint32_t crc) { // Construct a CrcCordState with a single chunk. crc_internal::CrcCordState state; state.mutable_rep()->prefix_crc.push_back( crc_internal::CrcCordState::PrefixCrc(size(), absl::crc32c_t{crc})); SetCrcCordState(std::move(state)); } const crc_internal::CrcCordState* Cord::MaybeGetCrcCordState() const { if (!contents_.is_tree() || !contents_.tree()->IsCrc()) { return nullptr; } return &contents_.tree()->crc()->crc_cord_state; } absl::optional Cord::ExpectedChecksum() const { if (!contents_.is_tree() || !contents_.tree()->IsCrc()) { return absl::nullopt; } return static_cast( contents_.tree()->crc()->crc_cord_state.Checksum()); } inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const { auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { if (!chunk->empty()) return true; ++*it; if (it->bytes_remaining_ == 0) return false; *chunk = **it; return true; }; Cord::ChunkIterator lhs_it = chunk_begin(); // compared_size is inside first chunk. absl::string_view lhs_chunk = (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); assert(compared_size <= lhs_chunk.size()); assert(compared_size <= rhs.size()); lhs_chunk.remove_prefix(compared_size); rhs.remove_prefix(compared_size); size_to_compare -= compared_size; // skip already compared size. while (advance(&lhs_it, &lhs_chunk) && !rhs.empty()) { int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare); if (comparison_result != 0) return comparison_result; if (size_to_compare == 0) return 0; } return static_cast(rhs.empty()) - static_cast(lhs_chunk.empty()); } inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size, size_t size_to_compare) const { auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { if (!chunk->empty()) return true; ++*it; if (it->bytes_remaining_ == 0) return false; *chunk = **it; return true; }; Cord::ChunkIterator lhs_it = chunk_begin(); Cord::ChunkIterator rhs_it = rhs.chunk_begin(); // compared_size is inside both first chunks. absl::string_view lhs_chunk = (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); absl::string_view rhs_chunk = (rhs_it.bytes_remaining_ != 0) ? *rhs_it : absl::string_view(); assert(compared_size <= lhs_chunk.size()); assert(compared_size <= rhs_chunk.size()); lhs_chunk.remove_prefix(compared_size); rhs_chunk.remove_prefix(compared_size); size_to_compare -= compared_size; // skip already compared size. while (advance(&lhs_it, &lhs_chunk) && advance(&rhs_it, &rhs_chunk)) { int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare); if (memcmp_res != 0) return memcmp_res; if (size_to_compare == 0) return 0; } return static_cast(rhs_chunk.empty()) - static_cast(lhs_chunk.empty()); } inline absl::string_view Cord::GetFirstChunk(const Cord& c) { if (c.empty()) return {}; return c.contents_.FindFlatStartPiece(); } inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) { return sv; } // Compares up to 'size_to_compare' bytes of 'lhs' with 'rhs'. It is assumed // that 'size_to_compare' is greater that size of smallest of first chunks. template ResultType GenericCompare(const Cord& lhs, const RHS& rhs, size_t size_to_compare) { absl::string_view lhs_chunk = Cord::GetFirstChunk(lhs); absl::string_view rhs_chunk = Cord::GetFirstChunk(rhs); size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size()); assert(size_to_compare >= compared_size); int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size); if (compared_size == size_to_compare || memcmp_res != 0) { return ComputeCompareResult(memcmp_res); } return ComputeCompareResult( lhs.CompareSlowPath(rhs, compared_size, size_to_compare)); } bool Cord::EqualsImpl(absl::string_view rhs, size_t size_to_compare) const { return GenericCompare(*this, rhs, size_to_compare); } bool Cord::EqualsImpl(const Cord& rhs, size_t size_to_compare) const { return GenericCompare(*this, rhs, size_to_compare); } template inline int SharedCompareImpl(const Cord& lhs, const RHS& rhs) { size_t lhs_size = lhs.size(); size_t rhs_size = rhs.size(); if (lhs_size == rhs_size) { return GenericCompare(lhs, rhs, lhs_size); } if (lhs_size < rhs_size) { auto data_comp_res = GenericCompare(lhs, rhs, lhs_size); return data_comp_res == 0 ? -1 : data_comp_res; } auto data_comp_res = GenericCompare(lhs, rhs, rhs_size); return data_comp_res == 0 ? +1 : data_comp_res; } int Cord::Compare(absl::string_view rhs) const { return SharedCompareImpl(*this, rhs); } int Cord::CompareImpl(const Cord& rhs) const { return SharedCompareImpl(*this, rhs); } bool Cord::EndsWith(absl::string_view rhs) const { size_t my_size = size(); size_t rhs_size = rhs.size(); if (my_size < rhs_size) return false; Cord tmp(*this); tmp.RemovePrefix(my_size - rhs_size); return tmp.EqualsImpl(rhs, rhs_size); } bool Cord::EndsWith(const Cord& rhs) const { size_t my_size = size(); size_t rhs_size = rhs.size(); if (my_size < rhs_size) return false; Cord tmp(*this); tmp.RemovePrefix(my_size - rhs_size); return tmp.EqualsImpl(rhs, rhs_size); } // -------------------------------------------------------------------- // Misc. Cord::operator std::string() const { std::string s; absl::CopyCordToString(*this, &s); return s; } void CopyCordToString(const Cord& src, std::string* dst) { if (!src.contents_.is_tree()) { src.contents_.CopyTo(dst); } else { absl::strings_internal::STLStringResizeUninitialized(dst, src.size()); src.CopyToArraySlowPath(&(*dst)[0]); } } void Cord::CopyToArraySlowPath(char* dst) const { assert(contents_.is_tree()); absl::string_view fragment; if (GetFlatAux(contents_.tree(), &fragment)) { memcpy(dst, fragment.data(), fragment.size()); return; } for (absl::string_view chunk : Chunks()) { memcpy(dst, chunk.data(), chunk.size()); dst += chunk.size(); } } Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); Cord subcord; auto constexpr method = CordzUpdateTracker::kCordReader; if (n <= InlineRep::kMaxInline) { // Range to read fits in inline data. Flatten it. char* data = subcord.contents_.set_data(n); while (n > current_chunk_.size()) { memcpy(data, current_chunk_.data(), current_chunk_.size()); data += current_chunk_.size(); n -= current_chunk_.size(); ++*this; } memcpy(data, current_chunk_.data(), n); if (n < current_chunk_.size()) { RemoveChunkPrefix(n); } else if (n > 0) { ++*this; } return subcord; } if (btree_reader_) { size_t chunk_size = current_chunk_.size(); if (n <= chunk_size && n <= kMaxBytesToCopy) { subcord = Cord(current_chunk_.substr(0, n), method); if (n < chunk_size) { current_chunk_.remove_prefix(n); } else { current_chunk_ = btree_reader_.Next(); } } else { CordRep* rep; current_chunk_ = btree_reader_.Read(n, chunk_size, rep); subcord.contents_.EmplaceTree(rep, method); } bytes_remaining_ -= n; return subcord; } // Short circuit if reading the entire data edge. assert(current_leaf_ != nullptr); if (n == current_leaf_->length) { bytes_remaining_ = 0; current_chunk_ = {}; CordRep* tree = CordRep::Ref(current_leaf_); subcord.contents_.EmplaceTree(VerifyTree(tree), method); return subcord; } // From this point on, we need a partial substring node. // Get pointer to the underlying flat or external data payload and // compute data pointer and offset into current flat or external. CordRep* payload = current_leaf_->IsSubstring() ? current_leaf_->substring()->child : current_leaf_; const char* data = payload->IsExternal() ? payload->external()->base : payload->flat()->Data(); const size_t offset = static_cast(current_chunk_.data() - data); auto* tree = CordRepSubstring::Substring(payload, offset, n); subcord.contents_.EmplaceTree(VerifyTree(tree), method); bytes_remaining_ -= n; current_chunk_.remove_prefix(n); return subcord; } char Cord::operator[](size_t i) const { ABSL_HARDENING_ASSERT(i < size()); size_t offset = i; const CordRep* rep = contents_.tree(); if (rep == nullptr) { return contents_.data()[i]; } rep = cord_internal::SkipCrcNode(rep); while (true) { assert(rep != nullptr); assert(offset < rep->length); if (rep->IsFlat()) { // Get the "i"th character directly from the flat array. return rep->flat()->Data()[offset]; } else if (rep->IsBtree()) { return rep->btree()->GetCharacter(offset); } else if (rep->IsExternal()) { // Get the "i"th character from the external array. return rep->external()->base[offset]; } else { // This must be a substring a node, so bypass it to get to the child. assert(rep->IsSubstring()); offset += rep->substring()->start; rep = rep->substring()->child; } } } absl::string_view Cord::FlattenSlowPath() { assert(contents_.is_tree()); size_t total_size = size(); CordRep* new_rep; char* new_buffer; // Try to put the contents into a new flat rep. If they won't fit in the // biggest possible flat node, use an external rep instead. if (total_size <= kMaxFlatLength) { new_rep = CordRepFlat::New(total_size); new_rep->length = total_size; new_buffer = new_rep->flat()->Data(); CopyToArraySlowPath(new_buffer); } else { new_buffer = std::allocator().allocate(total_size); CopyToArraySlowPath(new_buffer); new_rep = absl::cord_internal::NewExternalRep( absl::string_view(new_buffer, total_size), [](absl::string_view s) { std::allocator().deallocate(const_cast(s.data()), s.size()); }); } CordzUpdateScope scope(contents_.cordz_info(), CordzUpdateTracker::kFlatten); CordRep::Unref(contents_.as_tree()); contents_.SetTree(new_rep, scope); return absl::string_view(new_buffer, total_size); } /* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) { assert(rep != nullptr); if (rep->length == 0) { *fragment = absl::string_view(); return true; } rep = cord_internal::SkipCrcNode(rep); if (rep->IsFlat()) { *fragment = absl::string_view(rep->flat()->Data(), rep->length); return true; } else if (rep->IsExternal()) { *fragment = absl::string_view(rep->external()->base, rep->length); return true; } else if (rep->IsBtree()) { return rep->btree()->IsFlat(fragment); } else if (rep->IsSubstring()) { CordRep* child = rep->substring()->child; if (child->IsFlat()) { *fragment = absl::string_view( child->flat()->Data() + rep->substring()->start, rep->length); return true; } else if (child->IsExternal()) { *fragment = absl::string_view( child->external()->base + rep->substring()->start, rep->length); return true; } else if (child->IsBtree()) { return child->btree()->IsFlat(rep->substring()->start, rep->length, fragment); } } return false; } /* static */ void Cord::ForEachChunkAux( absl::cord_internal::CordRep* rep, absl::FunctionRef callback) { assert(rep != nullptr); if (rep->length == 0) return; rep = cord_internal::SkipCrcNode(rep); if (rep->IsBtree()) { ChunkIterator it(rep), end; while (it != end) { callback(*it); ++it; } return; } // This is a leaf node, so invoke our callback. absl::cord_internal::CordRep* current_node = cord_internal::SkipCrcNode(rep); absl::string_view chunk; bool success = GetFlatAux(current_node, &chunk); assert(success); if (success) { callback(chunk); } } static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, int indent) { const int kIndentStep = 1; absl::InlinedVector stack; absl::InlinedVector indents; for (;;) { *os << std::setw(3) << rep->refcount.Get(); *os << " " << std::setw(7) << rep->length; *os << " ["; if (include_data) *os << static_cast(rep); *os << "]"; *os << " " << std::setw(indent) << ""; bool leaf = false; if (rep == nullptr) { *os << "NULL\n"; leaf = true; } else if (rep->IsCrc()) { *os << "CRC crc=" << rep->crc()->crc_cord_state.Checksum() << "\n"; indent += kIndentStep; rep = rep->crc()->child; } else if (rep->IsSubstring()) { *os << "SUBSTRING @ " << rep->substring()->start << "\n"; indent += kIndentStep; rep = rep->substring()->child; } else { // Leaf or ring leaf = true; if (rep->IsExternal()) { *os << "EXTERNAL ["; if (include_data) *os << absl::CEscape(std::string(rep->external()->base, rep->length)); *os << "]\n"; } else if (rep->IsFlat()) { *os << "FLAT cap=" << rep->flat()->Capacity() << " ["; if (include_data) *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length)); *os << "]\n"; } else { CordRepBtree::Dump(rep, /*label=*/ "", include_data, *os); } } if (leaf) { if (stack.empty()) break; rep = stack.back(); stack.pop_back(); indent = indents.back(); indents.pop_back(); } } ABSL_INTERNAL_CHECK(indents.empty(), ""); } static std::string ReportError(CordRep* root, CordRep* node) { std::ostringstream buf; buf << "Error at node " << node << " in:"; DumpNode(root, true, &buf); return buf.str(); } static bool VerifyNode(CordRep* root, CordRep* start_node, bool /* full_validation */) { absl::InlinedVector worklist; worklist.push_back(start_node); do { CordRep* node = worklist.back(); worklist.pop_back(); ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node)); if (node != root) { ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node)); ABSL_INTERNAL_CHECK(!node->IsCrc(), ReportError(root, node)); } if (node->IsFlat()) { ABSL_INTERNAL_CHECK(node->length <= node->flat()->Capacity(), ReportError(root, node)); } else if (node->IsExternal()) { ABSL_INTERNAL_CHECK(node->external()->base != nullptr, ReportError(root, node)); } else if (node->IsSubstring()) { ABSL_INTERNAL_CHECK( node->substring()->start < node->substring()->child->length, ReportError(root, node)); ABSL_INTERNAL_CHECK(node->substring()->start + node->length <= node->substring()->child->length, ReportError(root, node)); } else if (node->IsCrc()) { ABSL_INTERNAL_CHECK( node->crc()->child != nullptr || node->crc()->length == 0, ReportError(root, node)); if (node->crc()->child != nullptr) { ABSL_INTERNAL_CHECK(node->crc()->length == node->crc()->child->length, ReportError(root, node)); worklist.push_back(node->crc()->child); } } } while (!worklist.empty()); return true; } std::ostream& operator<<(std::ostream& out, const Cord& cord) { for (absl::string_view chunk : cord.Chunks()) { out.write(chunk.data(), static_cast(chunk.size())); } return out; } namespace strings_internal { size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; } size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; } size_t CordTestAccess::FlatTagToLength(uint8_t tag) { return cord_internal::TagToLength(tag); } uint8_t CordTestAccess::LengthToTag(size_t s) { ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s)); return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead); } size_t CordTestAccess::SizeofCordRepExternal() { return sizeof(CordRepExternal); } size_t CordTestAccess::SizeofCordRepSubstring() { return sizeof(CordRepSubstring); } } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/cord.h0000644000175000017510000016777714737212474021163 0ustar nileshnilesh// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: cord.h // ----------------------------------------------------------------------------- // // This file defines the `absl::Cord` data structure and operations on that data // structure. A Cord is a string-like sequence of characters optimized for // specific use cases. Unlike a `std::string`, which stores an array of // contiguous characters, Cord data is stored in a structure consisting of // separate, reference-counted "chunks." // // Because a Cord consists of these chunks, data can be added to or removed from // a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a // `std::string`, a Cord can therefore accommodate data that changes over its // lifetime, though it's not quite "mutable"; it can change only in the // attachment, detachment, or rearrangement of chunks of its constituent data. // // A Cord provides some benefit over `std::string` under the following (albeit // narrow) circumstances: // // * Cord data is designed to grow and shrink over a Cord's lifetime. Cord // provides efficient insertions and deletions at the start and end of the // character sequences, avoiding copies in those cases. Static data should // generally be stored as strings. // * External memory consisting of string-like data can be directly added to // a Cord without requiring copies or allocations. // * Cord data may be shared and copied cheaply. Cord provides a copy-on-write // implementation and cheap sub-Cord operations. Copying a Cord is an O(1) // operation. // // As a consequence to the above, Cord data is generally large. Small data // should generally use strings, as construction of a Cord requires some // overhead. Small Cords (<= 15 bytes) are represented inline, but most small // Cords are expected to grow over their lifetimes. // // Note that because a Cord is made up of separate chunked data, random access // to character data within a Cord is slower than within a `std::string`. // // Thread Safety // // Cord has the same thread-safety properties as many other types like // std::string, std::vector<>, int, etc -- it is thread-compatible. In // particular, if threads do not call non-const methods, then it is safe to call // const methods without synchronization. Copying a Cord produces a new instance // that can be used concurrently with the original in arbitrary ways. #ifndef ABSL_STRINGS_CORD_H_ #define ABSL_STRINGS_CORD_H_ #include #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/macros.h" #include "absl/base/port.h" #include "absl/container/inlined_vector.h" #include "absl/crc/internal/crc_cord_state.h" #include "absl/functional/function_ref.h" #include "absl/meta/type_traits.h" #include "absl/strings/cord_analysis.h" #include "absl/strings/cord_buffer.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_reader.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cord_rep_ring.h" #include "absl/strings/internal/cordz_functions.h" #include "absl/strings/internal/cordz_info.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/string_constant.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN class Cord; class CordTestPeer; template Cord MakeCordFromExternal(absl::string_view, Releaser&&); void CopyCordToString(const Cord& src, std::string* dst); // Cord memory accounting modes enum class CordMemoryAccounting { // Counts the *approximate* number of bytes held in full or in part by this // Cord (which may not remain the same between invocations). Cords that share // memory could each be "charged" independently for the same shared memory. // See also comment on `kTotalMorePrecise` on internally shared memory. kTotal, // Counts the *approximate* number of bytes held in full or in part by this // Cord for the distinct memory held by this cord. This option is similar // to `kTotal`, except that if the cord has multiple references to the same // memory, that memory is only counted once. // // For example: // absl::Cord cord; // cord.append(some_other_cord); // cord.append(some_other_cord); // // Counts `some_other_cord` twice: // cord.EstimatedMemoryUsage(kTotal); // // Counts `some_other_cord` once: // cord.EstimatedMemoryUsage(kTotalMorePrecise); // // The `kTotalMorePrecise` number is more expensive to compute as it requires // deduplicating all memory references. Applications should prefer to use // `kFairShare` or `kTotal` unless they really need a more precise estimate // on "how much memory is potentially held / kept alive by this cord?" kTotalMorePrecise, // Counts the *approximate* number of bytes held in full or in part by this // Cord weighted by the sharing ratio of that data. For example, if some data // edge is shared by 4 different Cords, then each cord is attributed 1/4th of // the total memory usage as a 'fair share' of the total memory usage. kFairShare, }; // Cord // // A Cord is a sequence of characters, designed to be more efficient than a // `std::string` in certain circumstances: namely, large string data that needs // to change over its lifetime or shared, especially when such data is shared // across API boundaries. // // A Cord stores its character data in a structure that allows efficient prepend // and append operations. This makes a Cord useful for large string data sent // over in a wire format that may need to be prepended or appended at some point // during the data exchange (e.g. HTTP, protocol buffers). For example, a // Cord is useful for storing an HTTP request, and prepending an HTTP header to // such a request. // // Cords should not be used for storing general string data, however. They // require overhead to construct and are slower than strings for random access. // // The Cord API provides the following common API operations: // // * Create or assign Cords out of existing string data, memory, or other Cords // * Append and prepend data to an existing Cord // * Create new Sub-Cords from existing Cord data // * Swap Cord data and compare Cord equality // * Write out Cord data by constructing a `std::string` // // Additionally, the API provides iterator utilities to iterate through Cord // data via chunks or character bytes. // class Cord { private: template using EnableIfString = absl::enable_if_t::value, int>; public: // Cord::Cord() Constructors. // Creates an empty Cord. constexpr Cord() noexcept; // Creates a Cord from an existing Cord. Cord is copyable and efficiently // movable. The moved-from state is valid but unspecified. Cord(const Cord& src); Cord(Cord&& src) noexcept; Cord& operator=(const Cord& x); Cord& operator=(Cord&& x) noexcept; // Creates a Cord from a `src` string. This constructor is marked explicit to // prevent implicit Cord constructions from arguments convertible to an // `absl::string_view`. explicit Cord(absl::string_view src); Cord& operator=(absl::string_view src); // Creates a Cord from a `std::string&&` rvalue. These constructors are // templated to avoid ambiguities for types that are convertible to both // `absl::string_view` and `std::string`, such as `const char*`. template = 0> explicit Cord(T&& src); template = 0> Cord& operator=(T&& src); // Cord::~Cord() // // Destructs the Cord. ~Cord() { if (contents_.is_tree()) DestroyCordSlow(); } // MakeCordFromExternal() // // Creates a Cord that takes ownership of external string memory. The // contents of `data` are not copied to the Cord; instead, the external // memory is added to the Cord and reference-counted. This data may not be // changed for the life of the Cord, though it may be prepended or appended // to. // // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when // the reference count for `data` reaches zero. As noted above, this data must // remain live until the releaser is invoked. The callable releaser also must: // // * be move constructible // * support `void operator()(absl::string_view) const` or `void operator()` // // Example: // // Cord MakeCord(BlockPool* pool) { // Block* block = pool->NewBlock(); // FillBlock(block); // return absl::MakeCordFromExternal( // block->ToStringView(), // [pool, block](absl::string_view v) { // pool->FreeBlock(block, v); // }); // } // // WARNING: Because a Cord can be reference-counted, it's likely a bug if your // releaser doesn't do anything. For example, consider the following: // // void Foo(const char* buffer, int len) { // auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len), // [](absl::string_view) {}); // // // BUG: If Bar() copies its cord for any reason, including keeping a // // substring of it, the lifetime of buffer might be extended beyond // // when Foo() returns. // Bar(c); // } template friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser); // Cord::Clear() // // Releases the Cord data. Any nodes that share data with other Cords, if // applicable, will have their reference counts reduced by 1. ABSL_ATTRIBUTE_REINITIALIZES void Clear(); // Cord::Append() // // Appends data to the Cord, which may come from another Cord or other string // data. void Append(const Cord& src); void Append(Cord&& src); void Append(absl::string_view src); template = 0> void Append(T&& src); // Appends `buffer` to this cord, unless `buffer` has a zero length in which // case this method has no effect on this cord instance. // This method is guaranteed to consume `buffer`. void Append(CordBuffer buffer); // Returns a CordBuffer, re-using potential existing capacity in this cord. // // Cord instances may have additional unused capacity in the last (or first) // nodes of the underlying tree to facilitate amortized growth. This method // allows applications to explicitly use this spare capacity if available, // or create a new CordBuffer instance otherwise. // If this cord has a final non-shared node with at least `min_capacity` // available, then this method will return that buffer including its data // contents. I.e.; the returned buffer will have a non-zero length, and // a capacity of at least `buffer.length + min_capacity`. Otherwise, this // method will return `CordBuffer::CreateWithDefaultLimit(capacity)`. // // Below an example of using GetAppendBuffer. Notice that in this example we // use `GetAppendBuffer()` only on the first iteration. As we know nothing // about any initial extra capacity in `cord`, we may be able to use the extra // capacity. But as we add new buffers with fully utilized contents after that // we avoid calling `GetAppendBuffer()` on subsequent iterations: while this // works fine, it results in an unnecessary inspection of cord contents: // // void AppendRandomDataToCord(absl::Cord &cord, size_t n) { // bool first = true; // while (n > 0) { // CordBuffer buffer = first ? cord.GetAppendBuffer(n) // : CordBuffer::CreateWithDefaultLimit(n); // absl::Span data = buffer.available_up_to(n); // FillRandomValues(data.data(), data.size()); // buffer.IncreaseLengthBy(data.size()); // cord.Append(std::move(buffer)); // n -= data.size(); // first = false; // } // } CordBuffer GetAppendBuffer(size_t capacity, size_t min_capacity = 16); // Returns a CordBuffer, re-using potential existing capacity in this cord. // // This function is identical to `GetAppendBuffer`, except that in the case // where a new `CordBuffer` is allocated, it is allocated using the provided // custom limit instead of the default limit. `GetAppendBuffer` will default // to `CordBuffer::CreateWithDefaultLimit(capacity)` whereas this method // will default to `CordBuffer::CreateWithCustomLimit(block_size, capacity)`. // This method is equivalent to `GetAppendBuffer` if `block_size` is zero. // See the documentation for `CreateWithCustomLimit` for more details on the // restrictions and legal values for `block_size`. CordBuffer GetCustomAppendBuffer(size_t block_size, size_t capacity, size_t min_capacity = 16); // Cord::Prepend() // // Prepends data to the Cord, which may come from another Cord or other string // data. void Prepend(const Cord& src); void Prepend(absl::string_view src); template = 0> void Prepend(T&& src); // Prepends `buffer` to this cord, unless `buffer` has a zero length in which // case this method has no effect on this cord instance. // This method is guaranteed to consume `buffer`. void Prepend(CordBuffer buffer); // Cord::RemovePrefix() // // Removes the first `n` bytes of a Cord. void RemovePrefix(size_t n); void RemoveSuffix(size_t n); // Cord::Subcord() // // Returns a new Cord representing the subrange [pos, pos + new_size) of // *this. If pos >= size(), the result is empty(). If // (pos + new_size) >= size(), the result is the subrange [pos, size()). Cord Subcord(size_t pos, size_t new_size) const; // Cord::swap() // // Swaps the contents of the Cord with `other`. void swap(Cord& other) noexcept; // swap() // // Swaps the contents of two Cords. friend void swap(Cord& x, Cord& y) noexcept { x.swap(y); } // Cord::size() // // Returns the size of the Cord. size_t size() const; // Cord::empty() // // Determines whether the given Cord is empty, returning `true` is so. bool empty() const; // Cord::EstimatedMemoryUsage() // // Returns the *approximate* number of bytes held by this cord. // See CordMemoryAccounting for more information on the accounting method. size_t EstimatedMemoryUsage(CordMemoryAccounting accounting_method = CordMemoryAccounting::kTotal) const; // Cord::Compare() // // Compares 'this' Cord with rhs. This function and its relatives treat Cords // as sequences of unsigned bytes. The comparison is a straightforward // lexicographic comparison. `Cord::Compare()` returns values as follows: // // -1 'this' Cord is smaller // 0 two Cords are equal // 1 'this' Cord is larger int Compare(absl::string_view rhs) const; int Compare(const Cord& rhs) const; // Cord::StartsWith() // // Determines whether the Cord starts with the passed string data `rhs`. bool StartsWith(const Cord& rhs) const; bool StartsWith(absl::string_view rhs) const; // Cord::EndsWith() // // Determines whether the Cord ends with the passed string data `rhs`. bool EndsWith(absl::string_view rhs) const; bool EndsWith(const Cord& rhs) const; // Cord::operator std::string() // // Converts a Cord into a `std::string()`. This operator is marked explicit to // prevent unintended Cord usage in functions that take a string. explicit operator std::string() const; // CopyCordToString() // // Copies the contents of a `src` Cord into a `*dst` string. // // This function optimizes the case of reusing the destination string since it // can reuse previously allocated capacity. However, this function does not // guarantee that pointers previously returned by `dst->data()` remain valid // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new // object, prefer to simply use the conversion operator to `std::string`. friend void CopyCordToString(const Cord& src, std::string* dst); class CharIterator; //---------------------------------------------------------------------------- // Cord::ChunkIterator //---------------------------------------------------------------------------- // // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its // Cord. Such iteration allows you to perform non-const operations on the data // of a Cord without modifying it. // // Generally, you do not instantiate a `Cord::ChunkIterator` directly; // instead, you create one implicitly through use of the `Cord::Chunks()` // member function. // // The `Cord::ChunkIterator` has the following properties: // // * The iterator is invalidated after any non-const operation on the // Cord object over which it iterates. // * The `string_view` returned by dereferencing a valid, non-`end()` // iterator is guaranteed to be non-empty. // * Two `ChunkIterator` objects can be compared equal if and only if they // remain valid and iterate over the same Cord. // * The iterator in this case is a proxy iterator; the `string_view` // returned by the iterator does not live inside the Cord, and its // lifetime is limited to the lifetime of the iterator itself. To help // prevent lifetime issues, `ChunkIterator::reference` is not a true // reference type and is equivalent to `value_type`. // * The iterator keeps state that can grow for Cords that contain many // nodes and are imbalanced due to sharing. Prefer to pass this type by // const reference instead of by value. class ChunkIterator { public: using iterator_category = std::input_iterator_tag; using value_type = absl::string_view; using difference_type = ptrdiff_t; using pointer = const value_type*; using reference = value_type; ChunkIterator() = default; ChunkIterator& operator++(); ChunkIterator operator++(int); bool operator==(const ChunkIterator& other) const; bool operator!=(const ChunkIterator& other) const; reference operator*() const; pointer operator->() const; friend class Cord; friend class CharIterator; private: using CordRep = absl::cord_internal::CordRep; using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; // Constructs a `begin()` iterator from `tree`. `tree` must not be null. explicit ChunkIterator(cord_internal::CordRep* tree); // Constructs a `begin()` iterator from `cord`. explicit ChunkIterator(const Cord* cord); // Initializes this instance from a tree. Invoked by constructors. void InitTree(cord_internal::CordRep* tree); // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than // `current_chunk_.size()`. void RemoveChunkPrefix(size_t n); Cord AdvanceAndReadBytes(size_t n); void AdvanceBytes(size_t n); // Btree specific operator++ ChunkIterator& AdvanceBtree(); void AdvanceBytesBtree(size_t n); // A view into bytes of the current `CordRep`. It may only be a view to a // suffix of bytes if this is being used by `CharIterator`. absl::string_view current_chunk_; // The current leaf, or `nullptr` if the iterator points to short data. // If the current chunk is a substring node, current_leaf_ points to the // underlying flat or external node. absl::cord_internal::CordRep* current_leaf_ = nullptr; // The number of bytes left in the `Cord` over which we are iterating. size_t bytes_remaining_ = 0; // Cord reader for cord btrees. Empty if not traversing a btree. CordRepBtreeReader btree_reader_; }; // Cord::chunk_begin() // // Returns an iterator to the first chunk of the `Cord`. // // Generally, prefer using `Cord::Chunks()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `ChunkIterator` where range-based for-loops are not useful. // // Example: // // absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c, // absl::string_view s) { // return std::find(c.chunk_begin(), c.chunk_end(), s); // } ChunkIterator chunk_begin() const; // Cord::chunk_end() // // Returns an iterator one increment past the last chunk of the `Cord`. // // Generally, prefer using `Cord::Chunks()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `ChunkIterator` where range-based for-loops may not be available. ChunkIterator chunk_end() const; //---------------------------------------------------------------------------- // Cord::ChunkRange //---------------------------------------------------------------------------- // // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`, // producing an iterator which can be used within a range-based for loop. // Construction of a `ChunkRange` will return an iterator pointing to the // first chunk of the Cord. Generally, do not construct a `ChunkRange` // directly; instead, prefer to use the `Cord::Chunks()` method. // // Implementation note: `ChunkRange` is simply a convenience wrapper over // `Cord::chunk_begin()` and `Cord::chunk_end()`. class ChunkRange { public: // Fulfill minimum c++ container requirements [container.requirements] // These (partial) container type definitions allow ChunkRange to be used // in various utilities expecting a subset of [container.requirements]. // For example, the below enables using `::testing::ElementsAre(...)` using value_type = absl::string_view; using reference = value_type&; using const_reference = const value_type&; using iterator = ChunkIterator; using const_iterator = ChunkIterator; explicit ChunkRange(const Cord* cord) : cord_(cord) {} ChunkIterator begin() const; ChunkIterator end() const; private: const Cord* cord_; }; // Cord::Chunks() // // Returns a `Cord::ChunkRange` for iterating over the chunks of a `Cord` with // a range-based for-loop. For most iteration tasks on a Cord, use // `Cord::Chunks()` to retrieve this iterator. // // Example: // // void ProcessChunks(const Cord& cord) { // for (absl::string_view chunk : cord.Chunks()) { ... } // } // // Note that the ordinary caveats of temporary lifetime extension apply: // // void Process() { // for (absl::string_view chunk : CordFactory().Chunks()) { // // The temporary Cord returned by CordFactory has been destroyed! // } // } ChunkRange Chunks() const; //---------------------------------------------------------------------------- // Cord::CharIterator //---------------------------------------------------------------------------- // // A `Cord::CharIterator` allows iteration over the constituent characters of // a `Cord`. // // Generally, you do not instantiate a `Cord::CharIterator` directly; instead, // you create one implicitly through use of the `Cord::Chars()` member // function. // // A `Cord::CharIterator` has the following properties: // // * The iterator is invalidated after any non-const operation on the // Cord object over which it iterates. // * Two `CharIterator` objects can be compared equal if and only if they // remain valid and iterate over the same Cord. // * The iterator keeps state that can grow for Cords that contain many // nodes and are imbalanced due to sharing. Prefer to pass this type by // const reference instead of by value. // * This type cannot act as a forward iterator because a `Cord` can reuse // sections of memory. This fact violates the requirement for forward // iterators to compare equal if dereferencing them returns the same // object. class CharIterator { public: using iterator_category = std::input_iterator_tag; using value_type = char; using difference_type = ptrdiff_t; using pointer = const char*; using reference = const char&; CharIterator() = default; CharIterator& operator++(); CharIterator operator++(int); bool operator==(const CharIterator& other) const; bool operator!=(const CharIterator& other) const; reference operator*() const; pointer operator->() const; friend Cord; private: explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {} ChunkIterator chunk_iterator_; }; // Cord::AdvanceAndRead() // // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the // number of bytes within the Cord; otherwise, behavior is undefined. It is // valid to pass `char_end()` and `0`. static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes); // Cord::Advance() // // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than // or equal to the number of bytes remaining within the Cord; otherwise, // behavior is undefined. It is valid to pass `char_end()` and `0`. static void Advance(CharIterator* it, size_t n_bytes); // Cord::ChunkRemaining() // // Returns the longest contiguous view starting at the iterator's position. // // `it` must be dereferenceable. static absl::string_view ChunkRemaining(const CharIterator& it); // Cord::char_begin() // // Returns an iterator to the first character of the `Cord`. // // Generally, prefer using `Cord::Chars()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `CharIterator` where range-based for-loops may not be available. CharIterator char_begin() const; // Cord::char_end() // // Returns an iterator to one past the last character of the `Cord`. // // Generally, prefer using `Cord::Chars()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `CharIterator` where range-based for-loops are not useful. CharIterator char_end() const; // Cord::CharRange // // `CharRange` is a helper class for iterating over the characters of a // producing an iterator which can be used within a range-based for loop. // Construction of a `CharRange` will return an iterator pointing to the first // character of the Cord. Generally, do not construct a `CharRange` directly; // instead, prefer to use the `Cord::Chars()` method shown below. // // Implementation note: `CharRange` is simply a convenience wrapper over // `Cord::char_begin()` and `Cord::char_end()`. class CharRange { public: // Fulfill minimum c++ container requirements [container.requirements] // These (partial) container type definitions allow CharRange to be used // in various utilities expecting a subset of [container.requirements]. // For example, the below enables using `::testing::ElementsAre(...)` using value_type = char; using reference = value_type&; using const_reference = const value_type&; using iterator = CharIterator; using const_iterator = CharIterator; explicit CharRange(const Cord* cord) : cord_(cord) {} CharIterator begin() const; CharIterator end() const; private: const Cord* cord_; }; // Cord::Chars() // // Returns a `Cord::CharRange` for iterating over the characters of a `Cord` // with a range-based for-loop. For most character-based iteration tasks on a // Cord, use `Cord::Chars()` to retrieve this iterator. // // Example: // // void ProcessCord(const Cord& cord) { // for (char c : cord.Chars()) { ... } // } // // Note that the ordinary caveats of temporary lifetime extension apply: // // void Process() { // for (char c : CordFactory().Chars()) { // // The temporary Cord returned by CordFactory has been destroyed! // } // } CharRange Chars() const; // Cord::operator[] // // Gets the "i"th character of the Cord and returns it, provided that // 0 <= i < Cord.size(). // // NOTE: This routine is reasonably efficient. It is roughly // logarithmic based on the number of chunks that make up the cord. Still, // if you need to iterate over the contents of a cord, you should // use a CharIterator/ChunkIterator rather than call operator[] or Get() // repeatedly in a loop. char operator[](size_t i) const; // Cord::TryFlat() // // If this cord's representation is a single flat array, returns a // string_view referencing that array. Otherwise returns nullopt. absl::optional TryFlat() const; // Cord::Flatten() // // Flattens the cord into a single array and returns a view of the data. // // If the cord was already flat, the contents are not modified. absl::string_view Flatten(); // Supports absl::Cord as a sink object for absl::Format(). friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { cord->Append(part); } // Cord::SetExpectedChecksum() // // Stores a checksum value with this non-empty cord instance, for later // retrieval. // // The expected checksum is a number stored out-of-band, alongside the data. // It is preserved across copies and assignments, but any mutations to a cord // will cause it to lose its expected checksum. // // The expected checksum is not part of a Cord's value, and does not affect // operations such as equality or hashing. // // This field is intended to store a CRC32C checksum for later validation, to // help support end-to-end checksum workflows. However, the Cord API itself // does no CRC validation, and assigns no meaning to this number. // // This call has no effect if this cord is empty. void SetExpectedChecksum(uint32_t crc); // Returns this cord's expected checksum, if it has one. Otherwise, returns // nullopt. absl::optional ExpectedChecksum() const; template friend H AbslHashValue(H hash_state, const absl::Cord& c) { absl::optional maybe_flat = c.TryFlat(); if (maybe_flat.has_value()) { return H::combine(std::move(hash_state), *maybe_flat); } return c.HashFragmented(std::move(hash_state)); } // Create a Cord with the contents of StringConstant::value. // No allocations will be done and no data will be copied. // This is an INTERNAL API and subject to change or removal. This API can only // be used by spelling absl::strings_internal::MakeStringConstant, which is // also an internal API. template // NOLINTNEXTLINE(google-explicit-constructor) constexpr Cord(strings_internal::StringConstant); private: using CordRep = absl::cord_internal::CordRep; using CordRepFlat = absl::cord_internal::CordRepFlat; using CordzInfo = cord_internal::CordzInfo; using CordzUpdateScope = cord_internal::CordzUpdateScope; using CordzUpdateTracker = cord_internal::CordzUpdateTracker; using InlineData = cord_internal::InlineData; using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; // Creates a cord instance with `method` representing the originating // public API call causing the cord to be created. explicit Cord(absl::string_view src, MethodIdentifier method); friend class CordTestPeer; friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs); friend const CordzInfo* GetCordzInfoForTesting(const Cord& cord); // Calls the provided function once for each cord chunk, in order. Unlike // Chunks(), this API will not allocate memory. void ForEachChunk(absl::FunctionRef) const; // Allocates new contiguous storage for the contents of the cord. This is // called by Flatten() when the cord was not already flat. absl::string_view FlattenSlowPath(); // Actual cord contents are hidden inside the following simple // class so that we can isolate the bulk of cord.cc from changes // to the representation. // // InlineRep holds either a tree pointer, or an array of kMaxInline bytes. class InlineRep { public: static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), ""); constexpr InlineRep() : data_() {} explicit InlineRep(InlineData::DefaultInitType init) : data_(init) {} InlineRep(const InlineRep& src); InlineRep(InlineRep&& src); InlineRep& operator=(const InlineRep& src); InlineRep& operator=(InlineRep&& src) noexcept; explicit constexpr InlineRep(absl::string_view sv, CordRep* rep); void Swap(InlineRep* rhs); bool empty() const; size_t size() const; const char* data() const; // Returns nullptr if holding pointer void set_data(const char* data, size_t n); // Discards pointer, if any char* set_data(size_t n); // Write data to the result // Returns nullptr if holding bytes absl::cord_internal::CordRep* tree() const; absl::cord_internal::CordRep* as_tree() const; const char* as_chars() const; // Returns non-null iff was holding a pointer absl::cord_internal::CordRep* clear(); // Converts to pointer if necessary. void reduce_size(size_t n); // REQUIRES: holding data void remove_prefix(size_t n); // REQUIRES: holding data void AppendArray(absl::string_view src, MethodIdentifier method); absl::string_view FindFlatStartPiece() const; // Creates a CordRepFlat instance from the current inlined data with `extra' // bytes of desired additional capacity. CordRepFlat* MakeFlatWithExtraCapacity(size_t extra); // Sets the tree value for this instance. `rep` must not be null. // Requires the current instance to hold a tree, and a lock to be held on // any CordzInfo referenced by this instance. The latter is enforced through // the CordzUpdateScope argument. If the current instance is sampled, then // the CordzInfo instance is updated to reference the new `rep` value. void SetTree(CordRep* rep, const CordzUpdateScope& scope); // Identical to SetTree(), except that `rep` is allowed to be null, in // which case the current instance is reset to an empty value. void SetTreeOrEmpty(CordRep* rep, const CordzUpdateScope& scope); // Sets the tree value for this instance, and randomly samples this cord. // This function disregards existing contents in `data_`, and should be // called when a Cord is 'promoted' from an 'uninitialized' or 'inlined' // value to a non-inlined (tree / ring) value. void EmplaceTree(CordRep* rep, MethodIdentifier method); // Identical to EmplaceTree, except that it copies the parent stack from // the provided `parent` data if the parent is sampled. void EmplaceTree(CordRep* rep, const InlineData& parent, MethodIdentifier method); // Commits the change of a newly created, or updated `rep` root value into // this cord. `old_rep` indicates the old (inlined or tree) value of the // cord, and determines if the commit invokes SetTree() or EmplaceTree(). void CommitTree(const CordRep* old_rep, CordRep* rep, const CordzUpdateScope& scope, MethodIdentifier method); void AppendTreeToInlined(CordRep* tree, MethodIdentifier method); void AppendTreeToTree(CordRep* tree, MethodIdentifier method); void AppendTree(CordRep* tree, MethodIdentifier method); void PrependTreeToInlined(CordRep* tree, MethodIdentifier method); void PrependTreeToTree(CordRep* tree, MethodIdentifier method); void PrependTree(CordRep* tree, MethodIdentifier method); bool IsSame(const InlineRep& other) const { return data_ == other.data_; } void CopyTo(std::string* dst) const { // memcpy is much faster when operating on a known size. On most supported // platforms, the small string optimization is large enough that resizing // to 15 bytes does not cause a memory allocation. absl::strings_internal::STLStringResizeUninitialized(dst, kMaxInline); data_.copy_max_inline_to(&(*dst)[0]); // erase is faster than resize because the logic for memory allocation is // not needed. dst->erase(inline_size()); } // Copies the inline contents into `dst`. Assumes the cord is not empty. void CopyToArray(char* dst) const; bool is_tree() const { return data_.is_tree(); } // Returns true if the Cord is being profiled by cordz. bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } // Returns the available inlined capacity, or 0 if is_tree() == true. size_t remaining_inline_capacity() const { return data_.is_tree() ? 0 : kMaxInline - data_.inline_size(); } // Returns the profiled CordzInfo, or nullptr if not sampled. absl::cord_internal::CordzInfo* cordz_info() const { return data_.cordz_info(); } // Sets the profiled CordzInfo. `cordz_info` must not be null. void set_cordz_info(cord_internal::CordzInfo* cordz_info) { assert(cordz_info != nullptr); data_.set_cordz_info(cordz_info); } // Resets the current cordz_info to null / empty. void clear_cordz_info() { data_.clear_cordz_info(); } private: friend class Cord; void AssignSlow(const InlineRep& src); // Unrefs the tree and stops profiling. void UnrefTree(); void ResetToEmpty() { data_ = {}; } void set_inline_size(size_t size) { data_.set_inline_size(size); } size_t inline_size() const { return data_.inline_size(); } // Empty cords that carry a checksum have a CordRepCrc node with a null // child node. The code can avoid lots of special cases where it would // otherwise transition from tree to inline storage if we just remove the // CordRepCrc node before mutations. Must never be called inside a // CordzUpdateScope since it untracks the cordz info. void MaybeRemoveEmptyCrcNode(); cord_internal::InlineData data_; }; InlineRep contents_; // Helper for GetFlat() and TryFlat(). static bool GetFlatAux(absl::cord_internal::CordRep* rep, absl::string_view* fragment); // Helper for ForEachChunk(). static void ForEachChunkAux( absl::cord_internal::CordRep* rep, absl::FunctionRef callback); // The destructor for non-empty Cords. void DestroyCordSlow(); // Out-of-line implementation of slower parts of logic. void CopyToArraySlowPath(char* dst) const; int CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const; int CompareSlowPath(const Cord& rhs, size_t compared_size, size_t size_to_compare) const; bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const; bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const; int CompareImpl(const Cord& rhs) const; template friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs, size_t size_to_compare); static absl::string_view GetFirstChunk(const Cord& c); static absl::string_view GetFirstChunk(absl::string_view sv); // Returns a new reference to contents_.tree(), or steals an existing // reference if called on an rvalue. absl::cord_internal::CordRep* TakeRep() const&; absl::cord_internal::CordRep* TakeRep() &&; // Helper for Append(). template void AppendImpl(C&& src); // Appends / Prepends `src` to this instance, using precise sizing. // This method does explicitly not attempt to use any spare capacity // in any pending last added private owned flat. // Requires `src` to be <= kMaxFlatLength. void AppendPrecise(absl::string_view src, MethodIdentifier method); void PrependPrecise(absl::string_view src, MethodIdentifier method); CordBuffer GetAppendBufferSlowPath(size_t block_size, size_t capacity, size_t min_capacity); // Prepends the provided data to this instance. `method` contains the public // API method for this action which is tracked for Cordz sampling purposes. void PrependArray(absl::string_view src, MethodIdentifier method); // Assigns the value in 'src' to this instance, 'stealing' its contents. // Requires src.length() > kMaxBytesToCopy. Cord& AssignLargeString(std::string&& src); // Helper for AbslHashValue(). template H HashFragmented(H hash_state) const { typename H::AbslInternalPiecewiseCombiner combiner; ForEachChunk([&combiner, &hash_state](absl::string_view chunk) { hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(), chunk.size()); }); return H::combine(combiner.finalize(std::move(hash_state)), size()); } friend class CrcCord; void SetCrcCordState(crc_internal::CrcCordState state); const crc_internal::CrcCordState* MaybeGetCrcCordState() const; }; ABSL_NAMESPACE_END } // namespace absl namespace absl { ABSL_NAMESPACE_BEGIN // allow a Cord to be logged extern std::ostream& operator<<(std::ostream& out, const Cord& cord); // ------------------------------------------------------------------ // Internal details follow. Clients should ignore. namespace cord_internal { // Does non-template-specific `CordRepExternal` initialization. // Requires `data` to be non-empty. void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep); // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer // to it. Requires `data` to be non-empty. template // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { assert(!data.empty()); using ReleaserType = absl::decay_t; CordRepExternal* rep = new CordRepExternalImpl( std::forward(releaser), 0); InitializeCordRepExternal(data, rep); return rep; } // Overload for function reference types that dispatches using a function // pointer because there are no `alignof()` or `sizeof()` a function reference. // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. inline CordRep* NewExternalRep(absl::string_view data, void (&releaser)(absl::string_view)) { return NewExternalRep(data, &releaser); } } // namespace cord_internal template Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { Cord cord; if (ABSL_PREDICT_TRUE(!data.empty())) { cord.contents_.EmplaceTree(::absl::cord_internal::NewExternalRep( data, std::forward(releaser)), Cord::MethodIdentifier::kMakeCordFromExternal); } else { using ReleaserType = absl::decay_t; cord_internal::InvokeReleaser( cord_internal::Rank0{}, ReleaserType(std::forward(releaser)), data); } return cord; } constexpr Cord::InlineRep::InlineRep(absl::string_view sv, CordRep* rep) : data_(sv, rep) {} inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) : data_(InlineData::kDefaultInit) { if (CordRep* tree = src.tree()) { EmplaceTree(CordRep::Ref(tree), src.data_, CordzUpdateTracker::kConstructorCord); } else { data_ = src.data_; } } inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) : data_(src.data_) { src.ResetToEmpty(); } inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { if (this == &src) { return *this; } if (!is_tree() && !src.is_tree()) { data_ = src.data_; return *this; } AssignSlow(src); return *this; } inline Cord::InlineRep& Cord::InlineRep::operator=( Cord::InlineRep&& src) noexcept { if (is_tree()) { UnrefTree(); } data_ = src.data_; src.ResetToEmpty(); return *this; } inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { if (rhs == this) { return; } std::swap(data_, rhs->data_); } inline const char* Cord::InlineRep::data() const { return is_tree() ? nullptr : data_.as_chars(); } inline const char* Cord::InlineRep::as_chars() const { assert(!data_.is_tree()); return data_.as_chars(); } inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { assert(data_.is_tree()); return data_.as_tree(); } inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { if (is_tree()) { return as_tree(); } else { return nullptr; } } inline bool Cord::InlineRep::empty() const { return data_.is_empty(); } inline size_t Cord::InlineRep::size() const { return is_tree() ? as_tree()->length : inline_size(); } inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( size_t extra) { static_assert(cord_internal::kMinFlatLength >= sizeof(data_), ""); size_t len = data_.inline_size(); auto* result = CordRepFlat::New(len + extra); result->length = len; data_.copy_max_inline_to(result->Data()); return result; } inline void Cord::InlineRep::EmplaceTree(CordRep* rep, MethodIdentifier method) { assert(rep); data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, method); } inline void Cord::InlineRep::EmplaceTree(CordRep* rep, const InlineData& parent, MethodIdentifier method) { data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, parent, method); } inline void Cord::InlineRep::SetTree(CordRep* rep, const CordzUpdateScope& scope) { assert(rep); assert(data_.is_tree()); data_.set_tree(rep); scope.SetCordRep(rep); } inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, const CordzUpdateScope& scope) { assert(data_.is_tree()); if (rep) { data_.set_tree(rep); } else { data_ = {}; } scope.SetCordRep(rep); } inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, const CordzUpdateScope& scope, MethodIdentifier method) { if (old_rep) { SetTree(rep, scope); } else { EmplaceTree(rep, method); } } inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); } absl::cord_internal::CordRep* result = tree(); ResetToEmpty(); return result; } inline void Cord::InlineRep::CopyToArray(char* dst) const { assert(!is_tree()); size_t n = inline_size(); assert(n != 0); cord_internal::SmallMemmove(dst, data_.as_chars(), n); } inline void Cord::InlineRep::MaybeRemoveEmptyCrcNode() { CordRep* rep = tree(); if (rep == nullptr || ABSL_PREDICT_TRUE(rep->length > 0)) { return; } assert(rep->IsCrc()); assert(rep->crc()->child == nullptr); CordzInfo::MaybeUntrackCord(cordz_info()); CordRep::Unref(rep); ResetToEmpty(); } constexpr inline Cord::Cord() noexcept {} inline Cord::Cord(absl::string_view src) : Cord(src, CordzUpdateTracker::kConstructorString) {} template constexpr Cord::Cord(strings_internal::StringConstant) : contents_(strings_internal::StringConstant::value, strings_internal::StringConstant::value.size() <= cord_internal::kMaxInline ? nullptr : &cord_internal::ConstInitExternalStorage< strings_internal::StringConstant>::value) {} inline Cord& Cord::operator=(const Cord& x) { contents_ = x.contents_; return *this; } template > Cord& Cord::operator=(T&& src) { if (src.size() <= cord_internal::kMaxBytesToCopy) { return operator=(absl::string_view(src)); } else { return AssignLargeString(std::forward(src)); } } inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} inline void Cord::swap(Cord& other) noexcept { contents_.Swap(&other.contents_); } inline Cord& Cord::operator=(Cord&& x) noexcept { contents_ = std::move(x.contents_); return *this; } extern template Cord::Cord(std::string&& src); inline size_t Cord::size() const { // Length is 1st field in str.rep_ return contents_.size(); } inline bool Cord::empty() const { return size() == 0; } inline size_t Cord::EstimatedMemoryUsage( CordMemoryAccounting accounting_method) const { size_t result = sizeof(Cord); if (const absl::cord_internal::CordRep* rep = contents_.tree()) { switch (accounting_method) { case CordMemoryAccounting::kFairShare: result += cord_internal::GetEstimatedFairShareMemoryUsage(rep); break; case CordMemoryAccounting::kTotalMorePrecise: result += cord_internal::GetMorePreciseMemoryUsage(rep); break; case CordMemoryAccounting::kTotal: result += cord_internal::GetEstimatedMemoryUsage(rep); break; } } return result; } inline absl::optional Cord::TryFlat() const { absl::cord_internal::CordRep* rep = contents_.tree(); if (rep == nullptr) { return absl::string_view(contents_.data(), contents_.size()); } absl::string_view fragment; if (GetFlatAux(rep, &fragment)) { return fragment; } return absl::nullopt; } inline absl::string_view Cord::Flatten() { absl::cord_internal::CordRep* rep = contents_.tree(); if (rep == nullptr) { return absl::string_view(contents_.data(), contents_.size()); } else { absl::string_view already_flat_contents; if (GetFlatAux(rep, &already_flat_contents)) { return already_flat_contents; } } return FlattenSlowPath(); } inline void Cord::Append(absl::string_view src) { contents_.AppendArray(src, CordzUpdateTracker::kAppendString); } inline void Cord::Prepend(absl::string_view src) { PrependArray(src, CordzUpdateTracker::kPrependString); } inline void Cord::Append(CordBuffer buffer) { if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return; absl::string_view short_value; if (CordRep* rep = buffer.ConsumeValue(short_value)) { contents_.AppendTree(rep, CordzUpdateTracker::kAppendCordBuffer); } else { AppendPrecise(short_value, CordzUpdateTracker::kAppendCordBuffer); } } inline void Cord::Prepend(CordBuffer buffer) { if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return; absl::string_view short_value; if (CordRep* rep = buffer.ConsumeValue(short_value)) { contents_.PrependTree(rep, CordzUpdateTracker::kPrependCordBuffer); } else { PrependPrecise(short_value, CordzUpdateTracker::kPrependCordBuffer); } } inline CordBuffer Cord::GetAppendBuffer(size_t capacity, size_t min_capacity) { if (empty()) return CordBuffer::CreateWithDefaultLimit(capacity); return GetAppendBufferSlowPath(0, capacity, min_capacity); } inline CordBuffer Cord::GetCustomAppendBuffer(size_t block_size, size_t capacity, size_t min_capacity) { if (empty()) { return block_size ? CordBuffer::CreateWithCustomLimit(block_size, capacity) : CordBuffer::CreateWithDefaultLimit(capacity); } return GetAppendBufferSlowPath(block_size, capacity, min_capacity); } extern template void Cord::Append(std::string&& src); extern template void Cord::Prepend(std::string&& src); inline int Cord::Compare(const Cord& rhs) const { if (!contents_.is_tree() && !rhs.contents_.is_tree()) { return contents_.data_.Compare(rhs.contents_.data_); } return CompareImpl(rhs); } // Does 'this' cord start/end with rhs inline bool Cord::StartsWith(const Cord& rhs) const { if (contents_.IsSame(rhs.contents_)) return true; size_t rhs_size = rhs.size(); if (size() < rhs_size) return false; return EqualsImpl(rhs, rhs_size); } inline bool Cord::StartsWith(absl::string_view rhs) const { size_t rhs_size = rhs.size(); if (size() < rhs_size) return false; return EqualsImpl(rhs, rhs_size); } inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { tree = cord_internal::SkipCrcNode(tree); if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); } else { current_leaf_ = tree; current_chunk_ = cord_internal::EdgeData(tree); } } inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) { bytes_remaining_ = tree->length; InitTree(tree); } inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) { if (CordRep* tree = cord->contents_.tree()) { bytes_remaining_ = tree->length; if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) { InitTree(tree); } else { current_chunk_ = {}; } } else { bytes_remaining_ = cord->contents_.inline_size(); current_chunk_ = {cord->contents_.data(), bytes_remaining_}; } } inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceBtree() { current_chunk_ = btree_reader_.Next(); return *this; } inline void Cord::ChunkIterator::AdvanceBytesBtree(size_t n) { assert(n >= current_chunk_.size()); bytes_remaining_ -= n; if (bytes_remaining_) { if (n == current_chunk_.size()) { current_chunk_ = btree_reader_.Next(); } else { size_t offset = btree_reader_.length() - bytes_remaining_; current_chunk_ = btree_reader_.Seek(offset); } } else { current_chunk_ = {}; } } inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 && "Attempted to iterate past `end()`"); assert(bytes_remaining_ >= current_chunk_.size()); bytes_remaining_ -= current_chunk_.size(); if (bytes_remaining_ > 0) { if (btree_reader_) { return AdvanceBtree(); } else { assert(!current_chunk_.empty()); // Called on invalid iterator. } current_chunk_ = {}; } return *this; } inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) { ChunkIterator tmp(*this); operator++(); return tmp; } inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const { return bytes_remaining_ == other.bytes_remaining_; } inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const { return !(*this == other); } inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const { ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); return current_chunk_; } inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const { ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); return ¤t_chunk_; } inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) { assert(n < current_chunk_.size()); current_chunk_.remove_prefix(n); bytes_remaining_ -= n; } inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { assert(bytes_remaining_ >= n); if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { RemoveChunkPrefix(n); } else if (n != 0) { if (btree_reader_) { AdvanceBytesBtree(n); } else { bytes_remaining_ = 0; } } } inline Cord::ChunkIterator Cord::chunk_begin() const { return ChunkIterator(this); } inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); } inline Cord::ChunkIterator Cord::ChunkRange::begin() const { return cord_->chunk_begin(); } inline Cord::ChunkIterator Cord::ChunkRange::end() const { return cord_->chunk_end(); } inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); } inline Cord::CharIterator& Cord::CharIterator::operator++() { if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) { chunk_iterator_.RemoveChunkPrefix(1); } else { ++chunk_iterator_; } return *this; } inline Cord::CharIterator Cord::CharIterator::operator++(int) { CharIterator tmp(*this); operator++(); return tmp; } inline bool Cord::CharIterator::operator==(const CharIterator& other) const { return chunk_iterator_ == other.chunk_iterator_; } inline bool Cord::CharIterator::operator!=(const CharIterator& other) const { return !(*this == other); } inline Cord::CharIterator::reference Cord::CharIterator::operator*() const { return *chunk_iterator_->data(); } inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const { return chunk_iterator_->data(); } inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) { assert(it != nullptr); return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); } inline void Cord::Advance(CharIterator* it, size_t n_bytes) { assert(it != nullptr); it->chunk_iterator_.AdvanceBytes(n_bytes); } inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) { return *it.chunk_iterator_; } inline Cord::CharIterator Cord::char_begin() const { return CharIterator(this); } inline Cord::CharIterator Cord::char_end() const { return CharIterator(); } inline Cord::CharIterator Cord::CharRange::begin() const { return cord_->char_begin(); } inline Cord::CharIterator Cord::CharRange::end() const { return cord_->char_end(); } inline Cord::CharRange Cord::Chars() const { return CharRange(this); } inline void Cord::ForEachChunk( absl::FunctionRef callback) const { absl::cord_internal::CordRep* rep = contents_.tree(); if (rep == nullptr) { callback(absl::string_view(contents_.data(), contents_.size())); } else { ForEachChunkAux(rep, callback); } } // Nonmember Cord-to-Cord relational operators. inline bool operator==(const Cord& lhs, const Cord& rhs) { if (lhs.contents_.IsSame(rhs.contents_)) return true; size_t rhs_size = rhs.size(); if (lhs.size() != rhs_size) return false; return lhs.EqualsImpl(rhs, rhs_size); } inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); } inline bool operator<(const Cord& x, const Cord& y) { return x.Compare(y) < 0; } inline bool operator>(const Cord& x, const Cord& y) { return x.Compare(y) > 0; } inline bool operator<=(const Cord& x, const Cord& y) { return x.Compare(y) <= 0; } inline bool operator>=(const Cord& x, const Cord& y) { return x.Compare(y) >= 0; } // Nonmember Cord-to-absl::string_view relational operators. // // Due to implicit conversions, these also enable comparisons of Cord with // with std::string, ::string, and const char*. inline bool operator==(const Cord& lhs, absl::string_view rhs) { size_t lhs_size = lhs.size(); size_t rhs_size = rhs.size(); if (lhs_size != rhs_size) return false; return lhs.EqualsImpl(rhs, rhs_size); } inline bool operator==(absl::string_view x, const Cord& y) { return y == x; } inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); } inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); } inline bool operator<(const Cord& x, absl::string_view y) { return x.Compare(y) < 0; } inline bool operator<(absl::string_view x, const Cord& y) { return y.Compare(x) > 0; } inline bool operator>(const Cord& x, absl::string_view y) { return y < x; } inline bool operator>(absl::string_view x, const Cord& y) { return y < x; } inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); } inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); } inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); } inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); } // Some internals exposed to test code. namespace strings_internal { class CordTestAccess { public: static size_t FlatOverhead(); static size_t MaxFlatLength(); static size_t SizeofCordRepExternal(); static size_t SizeofCordRepSubstring(); static size_t FlatTagToLength(uint8_t tag); static uint8_t LengthToTag(size_t s); }; } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CORD_H_ s2/tools/vendor/abseil-cpp/absl/strings/str_split.h0000644000175000017510000004756314737212474022245 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: str_split.h // ----------------------------------------------------------------------------- // // This file contains functions for splitting strings. It defines the main // `StrSplit()` function, several delimiters for determining the boundaries on // which to split the string, and predicates for filtering delimited results. // `StrSplit()` adapts the returned collection to the type specified by the // caller. // // Example: // // // Splits the given string on commas. Returns the results in a // // vector of strings. // std::vector v = absl::StrSplit("a,b,c", ','); // // Can also use "," // // v[0] == "a", v[1] == "b", v[2] == "c" // // See StrSplit() below for more information. #ifndef ABSL_STRINGS_STR_SPLIT_H_ #define ABSL_STRINGS_STR_SPLIT_H_ #include #include #include #include #include #include #include #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/strings/internal/str_split_internal.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" namespace absl { ABSL_NAMESPACE_BEGIN //------------------------------------------------------------------------------ // Delimiters //------------------------------------------------------------------------------ // // `StrSplit()` uses delimiters to define the boundaries between elements in the // provided input. Several `Delimiter` types are defined below. If a string // (`const char*`, `std::string`, or `absl::string_view`) is passed in place of // an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it // were passed a `ByString` delimiter. // // A `Delimiter` is an object with a `Find()` function that knows how to find // the first occurrence of itself in a given `absl::string_view`. // // The following `Delimiter` types are available for use within `StrSplit()`: // // - `ByString` (default for string arguments) // - `ByChar` (default for a char argument) // - `ByAnyChar` // - `ByLength` // - `MaxSplits` // // A Delimiter's `Find()` member function will be passed an input `text` that is // to be split and a position (`pos`) to begin searching for the next delimiter // in `text`. The returned absl::string_view should refer to the next occurrence // (after `pos`) of the represented delimiter; this returned absl::string_view // represents the next location where the input `text` should be broken. // // The returned absl::string_view may be zero-length if the Delimiter does not // represent a part of the string (e.g., a fixed-length delimiter). If no // delimiter is found in the input `text`, a zero-length absl::string_view // referring to `text.end()` should be returned (e.g., // `text.substr(text.size())`). It is important that the returned // absl::string_view always be within the bounds of the input `text` given as an // argument--it must not refer to a string that is physically located outside of // the given string. // // The following example is a simple Delimiter object that is created with a // single char and will look for that char in the text passed to the `Find()` // function: // // struct SimpleDelimiter { // const char c_; // explicit SimpleDelimiter(char c) : c_(c) {} // absl::string_view Find(absl::string_view text, size_t pos) { // auto found = text.find(c_, pos); // if (found == absl::string_view::npos) // return text.substr(text.size()); // // return text.substr(found, 1); // } // }; // ByString // // A sub-string delimiter. If `StrSplit()` is passed a string in place of a // `Delimiter` object, the string will be implicitly converted into a // `ByString` delimiter. // // Example: // // // Because a string literal is converted to an `absl::ByString`, // // the following two splits are equivalent. // // std::vector v1 = absl::StrSplit("a, b, c", ", "); // // using absl::ByString; // std::vector v2 = absl::StrSplit("a, b, c", // ByString(", ")); // // v[0] == "a", v[1] == "b", v[2] == "c" class ByString { public: explicit ByString(absl::string_view sp); absl::string_view Find(absl::string_view text, size_t pos) const; private: const std::string delimiter_; }; // ByChar // // A single character delimiter. `ByChar` is functionally equivalent to a // 1-char string within a `ByString` delimiter, but slightly more efficient. // // Example: // // // Because a char literal is converted to a absl::ByChar, // // the following two splits are equivalent. // std::vector v1 = absl::StrSplit("a,b,c", ','); // using absl::ByChar; // std::vector v2 = absl::StrSplit("a,b,c", ByChar(',')); // // v[0] == "a", v[1] == "b", v[2] == "c" // // `ByChar` is also the default delimiter if a single character is given // as the delimiter to `StrSplit()`. For example, the following calls are // equivalent: // // std::vector v = absl::StrSplit("a-b", '-'); // // using absl::ByChar; // std::vector v = absl::StrSplit("a-b", ByChar('-')); // class ByChar { public: explicit ByChar(char c) : c_(c) {} absl::string_view Find(absl::string_view text, size_t pos) const; private: char c_; }; // ByAnyChar // // A delimiter that will match any of the given byte-sized characters within // its provided string. // // Note: this delimiter works with single-byte string data, but does not work // with variable-width encodings, such as UTF-8. // // Example: // // using absl::ByAnyChar; // std::vector v = absl::StrSplit("a,b=c", ByAnyChar(",=")); // // v[0] == "a", v[1] == "b", v[2] == "c" // // If `ByAnyChar` is given the empty string, it behaves exactly like // `ByString` and matches each individual character in the input string. // class ByAnyChar { public: explicit ByAnyChar(absl::string_view sp); absl::string_view Find(absl::string_view text, size_t pos) const; private: const std::string delimiters_; }; // ByLength // // A delimiter for splitting into equal-length strings. The length argument to // the constructor must be greater than 0. // // Note: this delimiter works with single-byte string data, but does not work // with variable-width encodings, such as UTF-8. // // Example: // // using absl::ByLength; // std::vector v = absl::StrSplit("123456789", ByLength(3)); // // v[0] == "123", v[1] == "456", v[2] == "789" // // Note that the string does not have to be a multiple of the fixed split // length. In such a case, the last substring will be shorter. // // using absl::ByLength; // std::vector v = absl::StrSplit("12345", ByLength(2)); // // // v[0] == "12", v[1] == "34", v[2] == "5" class ByLength { public: explicit ByLength(ptrdiff_t length); absl::string_view Find(absl::string_view text, size_t pos) const; private: const ptrdiff_t length_; }; namespace strings_internal { // A traits-like metafunction for selecting the default Delimiter object type // for a particular Delimiter type. The base case simply exposes type Delimiter // itself as the delimiter's Type. However, there are specializations for // string-like objects that map them to the ByString delimiter object. // This allows functions like absl::StrSplit() and absl::MaxSplits() to accept // string-like objects (e.g., ',') as delimiter arguments but they will be // treated as if a ByString delimiter was given. template struct SelectDelimiter { using type = Delimiter; }; template <> struct SelectDelimiter { using type = ByChar; }; template <> struct SelectDelimiter { using type = ByString; }; template <> struct SelectDelimiter { using type = ByString; }; template <> struct SelectDelimiter { using type = ByString; }; template <> struct SelectDelimiter { using type = ByString; }; // Wraps another delimiter and sets a max number of matches for that delimiter. template class MaxSplitsImpl { public: MaxSplitsImpl(Delimiter delimiter, int limit) : delimiter_(delimiter), limit_(limit), count_(0) {} absl::string_view Find(absl::string_view text, size_t pos) { if (count_++ == limit_) { return absl::string_view(text.data() + text.size(), 0); // No more matches. } return delimiter_.Find(text, pos); } private: Delimiter delimiter_; const int limit_; int count_; }; } // namespace strings_internal // MaxSplits() // // A delimiter that limits the number of matches which can occur to the passed // `limit`. The last element in the returned collection will contain all // remaining unsplit pieces, which may contain instances of the delimiter. // The collection will contain at most `limit` + 1 elements. // Example: // // using absl::MaxSplits; // std::vector v = absl::StrSplit("a,b,c", MaxSplits(',', 1)); // // // v[0] == "a", v[1] == "b,c" template inline strings_internal::MaxSplitsImpl< typename strings_internal::SelectDelimiter::type> MaxSplits(Delimiter delimiter, int limit) { typedef typename strings_internal::SelectDelimiter::type DelimiterType; return strings_internal::MaxSplitsImpl( DelimiterType(delimiter), limit); } //------------------------------------------------------------------------------ // Predicates //------------------------------------------------------------------------------ // // Predicates filter the results of a `StrSplit()` by determining whether or not // a resultant element is included in the result set. A predicate may be passed // as an optional third argument to the `StrSplit()` function. // // Predicates are unary functions (or functors) that take a single // `absl::string_view` argument and return a bool indicating whether the // argument should be included (`true`) or excluded (`false`). // // Predicates are useful when filtering out empty substrings. By default, empty // substrings may be returned by `StrSplit()`, which is similar to the way split // functions work in other programming languages. // AllowEmpty() // // Always returns `true`, indicating that all strings--including empty // strings--should be included in the split output. This predicate is not // strictly needed because this is the default behavior of `StrSplit()`; // however, it might be useful at some call sites to make the intent explicit. // // Example: // // std::vector v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty()); // // // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == "" struct AllowEmpty { bool operator()(absl::string_view) const { return true; } }; // SkipEmpty() // // Returns `false` if the given `absl::string_view` is empty, indicating that // `StrSplit()` should omit the empty string. // // Example: // // std::vector v = absl::StrSplit(",a,,b,", ',', SkipEmpty()); // // // v[0] == "a", v[1] == "b" // // Note: `SkipEmpty()` does not consider a string containing only whitespace // to be empty. To skip such whitespace as well, use the `SkipWhitespace()` // predicate. struct SkipEmpty { bool operator()(absl::string_view sp) const { return !sp.empty(); } }; // SkipWhitespace() // // Returns `false` if the given `absl::string_view` is empty *or* contains only // whitespace, indicating that `StrSplit()` should omit the string. // // Example: // // std::vector v = absl::StrSplit(" a , ,,b,", // ',', SkipWhitespace()); // // v[0] == " a ", v[1] == "b" // // // SkipEmpty() would return whitespace elements // std::vector v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty()); // // v[0] == " a ", v[1] == " ", v[2] == "b" struct SkipWhitespace { bool operator()(absl::string_view sp) const { sp = absl::StripAsciiWhitespace(sp); return !sp.empty(); } }; template using EnableSplitIfString = typename std::enable_if::value || std::is_same::value, int>::type; //------------------------------------------------------------------------------ // StrSplit() //------------------------------------------------------------------------------ // StrSplit() // // Splits a given string based on the provided `Delimiter` object, returning the // elements within the type specified by the caller. Optionally, you may pass a // `Predicate` to `StrSplit()` indicating whether to include or exclude the // resulting element within the final result set. (See the overviews for // Delimiters and Predicates above.) // // Example: // // std::vector v = absl::StrSplit("a,b,c,d", ','); // // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d" // // You can also provide an explicit `Delimiter` object: // // Example: // // using absl::ByAnyChar; // std::vector v = absl::StrSplit("a,b=c", ByAnyChar(",=")); // // v[0] == "a", v[1] == "b", v[2] == "c" // // See above for more information on delimiters. // // By default, empty strings are included in the result set. You can optionally // include a third `Predicate` argument to apply a test for whether the // resultant element should be included in the result set: // // Example: // // std::vector v = absl::StrSplit(" a , ,,b,", // ',', SkipWhitespace()); // // v[0] == " a ", v[1] == "b" // // See above for more information on predicates. // //------------------------------------------------------------------------------ // StrSplit() Return Types //------------------------------------------------------------------------------ // // The `StrSplit()` function adapts the returned collection to the collection // specified by the caller (e.g. `std::vector` above). The returned collections // may contain `std::string`, `absl::string_view` (in which case the original // string being split must ensure that it outlives the collection), or any // object that can be explicitly created from an `absl::string_view`. This // behavior works for: // // 1) All standard STL containers including `std::vector`, `std::list`, // `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap` // 2) `std::pair` (which is not actually a container). See below. // // Example: // // // The results are returned as `absl::string_view` objects. Note that we // // have to ensure that the input string outlives any results. // std::vector v = absl::StrSplit("a,b,c", ','); // // // Stores results in a std::set, which also performs // // de-duplication and orders the elements in ascending order. // std::set a = absl::StrSplit("b,a,c,a,b", ','); // // v[0] == "a", v[1] == "b", v[2] = "c" // // // `StrSplit()` can be used within a range-based for loop, in which case // // each element will be of type `absl::string_view`. // std::vector v; // for (const auto sv : absl::StrSplit("a,b,c", ',')) { // if (sv != "b") v.emplace_back(sv); // } // // v[0] == "a", v[1] == "c" // // // Stores results in a map. The map implementation assumes that the input // // is provided as a series of key/value pairs. For example, the 0th element // // resulting from the split will be stored as a key to the 1st element. If // // an odd number of elements are resolved, the last element is paired with // // a default-constructed value (e.g., empty string). // std::map m = absl::StrSplit("a,b,c", ','); // // m["a"] == "b", m["c"] == "" // last component value equals "" // // Splitting to `std::pair` is an interesting case because it can hold only two // elements and is not a collection type. When splitting to a `std::pair` the // first two split strings become the `std::pair` `.first` and `.second` // members, respectively. The remaining split substrings are discarded. If there // are less than two split substrings, the empty string is used for the // corresponding `std::pair` member. // // Example: // // // Stores first two split strings as the members in a std::pair. // std::pair p = absl::StrSplit("a,b,c", ','); // // p.first == "a", p.second == "b" // "c" is omitted. // // The `StrSplit()` function can be used multiple times to perform more // complicated splitting logic, such as intelligently parsing key-value pairs. // // Example: // // // The input string "a=b=c,d=e,f=,g" becomes // // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } // std::map m; // for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) { // m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1))); // } // EXPECT_EQ("b=c", m.find("a")->second); // EXPECT_EQ("e", m.find("d")->second); // EXPECT_EQ("", m.find("f")->second); // EXPECT_EQ("", m.find("g")->second); // // WARNING: Due to a legacy bug that is maintained for backward compatibility, // splitting the following empty string_views produces different results: // // absl::StrSplit(absl::string_view(""), '-'); // {""} // absl::StrSplit(absl::string_view(), '-'); // {}, but should be {""} // // Try not to depend on this distinction because the bug may one day be fixed. template strings_internal::Splitter< typename strings_internal::SelectDelimiter::type, AllowEmpty, absl::string_view> StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { using DelimiterType = typename strings_internal::SelectDelimiter::type; return strings_internal::Splitter( text.value(), DelimiterType(d), AllowEmpty()); } template = 0> strings_internal::Splitter< typename strings_internal::SelectDelimiter::type, AllowEmpty, std::string> StrSplit(StringType&& text, Delimiter d) { using DelimiterType = typename strings_internal::SelectDelimiter::type; return strings_internal::Splitter( std::move(text), DelimiterType(d), AllowEmpty()); } template strings_internal::Splitter< typename strings_internal::SelectDelimiter::type, Predicate, absl::string_view> StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, Predicate p) { using DelimiterType = typename strings_internal::SelectDelimiter::type; return strings_internal::Splitter( text.value(), DelimiterType(d), std::move(p)); } template = 0> strings_internal::Splitter< typename strings_internal::SelectDelimiter::type, Predicate, std::string> StrSplit(StringType&& text, Delimiter d, Predicate p) { using DelimiterType = typename strings_internal::SelectDelimiter::type; return strings_internal::Splitter( std::move(text), DelimiterType(d), std::move(p)); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_SPLIT_H_ s2/tools/vendor/abseil-cpp/absl/strings/string_view.cc0000644000175000017510000001572614737212474022714 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/string_view.h" #ifndef ABSL_USES_STD_STRING_VIEW #include #include #include #include namespace absl { ABSL_NAMESPACE_BEGIN namespace { // This is significantly faster for case-sensitive matches with very // few possible matches. const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, size_t neelen) { if (0 == neelen) { return phaystack; // even if haylen is 0 } if (haylen < neelen) return nullptr; const char* match; const char* hayend = phaystack + haylen - neelen + 1; // A static cast is used here to work around the fact that memchr returns // a void* on Posix-compliant systems and const void* on Windows. while ( (match = static_cast(memchr( phaystack, pneedle[0], static_cast(hayend - phaystack))))) { if (memcmp(match, pneedle, neelen) == 0) return match; else phaystack = match + 1; } return nullptr; } void WritePadding(std::ostream& o, size_t pad) { char fill_buf[32]; memset(fill_buf, o.fill(), sizeof(fill_buf)); while (pad) { size_t n = std::min(pad, sizeof(fill_buf)); o.write(fill_buf, static_cast(n)); pad -= n; } } class LookupTable { public: // For each character in wanted, sets the index corresponding // to the ASCII code of that character. This is used by // the find_.*_of methods below to tell whether or not a character is in // the lookup table in constant time. explicit LookupTable(string_view wanted) { for (char c : wanted) { table_[Index(c)] = true; } } bool operator[](char c) const { return table_[Index(c)]; } private: static unsigned char Index(char c) { return static_cast(c); } bool table_[UCHAR_MAX + 1] = {}; }; } // namespace std::ostream& operator<<(std::ostream& o, string_view piece) { std::ostream::sentry sentry(o); if (sentry) { size_t lpad = 0; size_t rpad = 0; if (static_cast(o.width()) > piece.size()) { size_t pad = static_cast(o.width()) - piece.size(); if ((o.flags() & o.adjustfield) == o.left) { rpad = pad; } else { lpad = pad; } } if (lpad) WritePadding(o, lpad); o.write(piece.data(), static_cast(piece.size())); if (rpad) WritePadding(o, rpad); o.width(0); } return o; } string_view::size_type string_view::find(string_view s, size_type pos) const noexcept { if (empty() || pos > length_) { if (empty() && pos == 0 && s.empty()) return 0; return npos; } const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); return result ? static_cast(result - ptr_) : npos; } string_view::size_type string_view::find(char c, size_type pos) const noexcept { if (empty() || pos >= length_) { return npos; } const char* result = static_cast(memchr(ptr_ + pos, c, length_ - pos)); return result != nullptr ? static_cast(result - ptr_) : npos; } string_view::size_type string_view::rfind(string_view s, size_type pos) const noexcept { if (length_ < s.length_) return npos; if (s.empty()) return std::min(length_, pos); const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); return result != last ? static_cast(result - ptr_) : npos; } // Search range is [0..pos] inclusive. If pos == npos, search everything. string_view::size_type string_view::rfind(char c, size_type pos) const noexcept { // Note: memrchr() is not available on Windows. if (empty()) return npos; for (size_type i = std::min(pos, length_ - 1);; --i) { if (ptr_[i] == c) { return i; } if (i == 0) break; } return npos; } string_view::size_type string_view::find_first_of( string_view s, size_type pos) const noexcept { if (empty() || s.empty()) { return npos; } // Avoid the cost of LookupTable() for a single-character search. if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); LookupTable tbl(s); for (size_type i = pos; i < length_; ++i) { if (tbl[ptr_[i]]) { return i; } } return npos; } string_view::size_type string_view::find_first_not_of( string_view s, size_type pos) const noexcept { if (empty()) return npos; // Avoid the cost of LookupTable() for a single-character search. if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); LookupTable tbl(s); for (size_type i = pos; i < length_; ++i) { if (!tbl[ptr_[i]]) { return i; } } return npos; } string_view::size_type string_view::find_first_not_of( char c, size_type pos) const noexcept { if (empty()) return npos; for (; pos < length_; ++pos) { if (ptr_[pos] != c) { return pos; } } return npos; } string_view::size_type string_view::find_last_of(string_view s, size_type pos) const noexcept { if (empty() || s.empty()) return npos; // Avoid the cost of LookupTable() for a single-character search. if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); LookupTable tbl(s); for (size_type i = std::min(pos, length_ - 1);; --i) { if (tbl[ptr_[i]]) { return i; } if (i == 0) break; } return npos; } string_view::size_type string_view::find_last_not_of( string_view s, size_type pos) const noexcept { if (empty()) return npos; size_type i = std::min(pos, length_ - 1); if (s.empty()) return i; // Avoid the cost of LookupTable() for a single-character search. if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); LookupTable tbl(s); for (;; --i) { if (!tbl[ptr_[i]]) { return i; } if (i == 0) break; } return npos; } string_view::size_type string_view::find_last_not_of( char c, size_type pos) const noexcept { if (empty()) return npos; size_type i = std::min(pos, length_ - 1); for (;; --i) { if (ptr_[i] != c) { return i; } if (i == 0) break; } return npos; } #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr string_view::size_type string_view::npos; constexpr string_view::size_type string_view::kMaxSize; #endif ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_USES_STD_STRING_VIEW s2/tools/vendor/abseil-cpp/absl/strings/str_cat.h0000644000175000017510000004742614737212474021657 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: str_cat.h // ----------------------------------------------------------------------------- // // This package contains functions for efficiently concatenating and appending // strings: `StrCat()` and `StrAppend()`. Most of the work within these routines // is actually handled through use of a special AlphaNum type, which was // designed to be used as a parameter type that efficiently manages conversion // to strings and avoids copies in the above operations. // // Any routine accepting either a string or a number may accept `AlphaNum`. // The basic idea is that by accepting a `const AlphaNum &` as an argument // to your function, your callers will automagically convert bools, integers, // and floating point values to strings for you. // // NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported // except for the specific case of function parameters of type `AlphaNum` or // `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a // stack variable is not supported. // // Conversion from 8-bit values is not accepted because, if it were, then an // attempt to pass ':' instead of ":" might result in a 58 ending up in your // result. // // Bools convert to "0" or "1". Pointers to types other than `char *` are not // valid inputs. No output is generated for null `char *` pointers. // // Floating point numbers are formatted with six-digit precision, which is // the default for "std::cout <<" or printf "%g" (the same as "%.6g"). // // You can convert to hexadecimal output rather than decimal output using the // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using // a `PadSpec` enum. // // User-defined types can be formatted with the `AbslStringify()` customization // point. The API relies on detecting an overload in the user-defined type's // namespace of a free (non-member) `AbslStringify()` function as a definition // (typically declared as a friend and implemented in-line. // with the following signature: // // class MyClass { ... }; // // template // void AbslStringify(Sink& sink, const MyClass& value); // // An `AbslStringify()` overload for a type should only be declared in the same // file and namespace as said type. // // Note that `AbslStringify()` also supports use with `absl::StrFormat()` and // `absl::Substitute()`. // // Example: // // struct Point { // // To add formatting support to `Point`, we simply need to add a free // // (non-member) function `AbslStringify()`. This method specifies how // // Point should be printed when absl::StrCat() is called on it. You can add // // such a free function using a friend declaration within the body of the // // class. The sink parameter is a templated type to avoid requiring // // dependencies. // template friend void AbslStringify(Sink& // sink, const Point& p) { // absl::Format(&sink, "(%v, %v)", p.x, p.y); // } // // int x; // int y; // }; // ----------------------------------------------------------------------------- #ifndef ABSL_STRINGS_STR_CAT_H_ #define ABSL_STRINGS_STR_CAT_H_ #include #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/port.h" #include "absl/strings/internal/has_absl_stringify.h" #include "absl/strings/internal/stringify_sink.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { // AlphaNumBuffer allows a way to pass a string to StrCat without having to do // memory allocation. It is simply a pair of a fixed-size character array, and // a size. Please don't use outside of absl, yet. template struct AlphaNumBuffer { std::array data; size_t size; }; } // namespace strings_internal // Enum that specifies the number of significant digits to return in a `Hex` or // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, // would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value // would produce hexadecimal strings such as " a"," f". enum PadSpec : uint8_t { kNoPad = 1, kZeroPad2, kZeroPad3, kZeroPad4, kZeroPad5, kZeroPad6, kZeroPad7, kZeroPad8, kZeroPad9, kZeroPad10, kZeroPad11, kZeroPad12, kZeroPad13, kZeroPad14, kZeroPad15, kZeroPad16, kZeroPad17, kZeroPad18, kZeroPad19, kZeroPad20, kSpacePad2 = kZeroPad2 + 64, kSpacePad3, kSpacePad4, kSpacePad5, kSpacePad6, kSpacePad7, kSpacePad8, kSpacePad9, kSpacePad10, kSpacePad11, kSpacePad12, kSpacePad13, kSpacePad14, kSpacePad15, kSpacePad16, kSpacePad17, kSpacePad18, kSpacePad19, kSpacePad20, }; // ----------------------------------------------------------------------------- // Hex // ----------------------------------------------------------------------------- // // `Hex` stores a set of hexadecimal string conversion parameters for use // within `AlphaNum` string conversions. struct Hex { uint64_t value; uint8_t width; char fill; template explicit Hex( Int v, PadSpec spec = absl::kNoPad, typename std::enable_if::value>::type* = nullptr) : Hex(spec, static_cast(v)) {} template explicit Hex( Int v, PadSpec spec = absl::kNoPad, typename std::enable_if::value>::type* = nullptr) : Hex(spec, static_cast(v)) {} template explicit Hex( Int v, PadSpec spec = absl::kNoPad, typename std::enable_if::value>::type* = nullptr) : Hex(spec, static_cast(v)) {} template explicit Hex( Int v, PadSpec spec = absl::kNoPad, typename std::enable_if::value>::type* = nullptr) : Hex(spec, static_cast(v)) {} template explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad) : Hex(spec, reinterpret_cast(v)) {} template friend void AbslStringify(S& sink, Hex hex) { static_assert( numbers_internal::kFastToBufferSize >= 32, "This function only works when output buffer >= 32 bytes long"); char buffer[numbers_internal::kFastToBufferSize]; char* const end = &buffer[numbers_internal::kFastToBufferSize]; auto real_width = absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16); if (real_width >= hex.width) { sink.Append(absl::string_view(end - real_width, real_width)); } else { // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and // max pad width can be up to 20. std::memset(end - 32, hex.fill, 16); // Patch up everything else up to the real_width. std::memset(end - real_width - 16, hex.fill, 16); sink.Append(absl::string_view(end - hex.width, hex.width)); } } private: Hex(PadSpec spec, uint64_t v) : value(v), width(spec == absl::kNoPad ? 1 : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 : spec - absl::kZeroPad2 + 2), fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} }; // ----------------------------------------------------------------------------- // Dec // ----------------------------------------------------------------------------- // // `Dec` stores a set of decimal string conversion parameters for use // within `AlphaNum` string conversions. Dec is slower than the default // integer conversion, so use it only if you need padding. struct Dec { uint64_t value; uint8_t width; char fill; bool neg; template explicit Dec(Int v, PadSpec spec = absl::kNoPad, typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) : value(v >= 0 ? static_cast(v) : uint64_t{0} - static_cast(v)), width(spec == absl::kNoPad ? 1 : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 : spec - absl::kZeroPad2 + 2), fill(spec >= absl::kSpacePad2 ? ' ' : '0'), neg(v < 0) {} template friend void AbslStringify(S& sink, Dec dec) { assert(dec.width <= numbers_internal::kFastToBufferSize); char buffer[numbers_internal::kFastToBufferSize]; char* const end = &buffer[numbers_internal::kFastToBufferSize]; char* const minfill = end - dec.width; char* writer = end; uint64_t val = dec.value; while (val > 9) { *--writer = '0' + (val % 10); val /= 10; } *--writer = '0' + static_cast(val); if (dec.neg) *--writer = '-'; ptrdiff_t fillers = writer - minfill; if (fillers > 0) { // Tricky: if the fill character is ' ', then it's <+/-> // But...: if the fill character is '0', then it's <+/-> bool add_sign_again = false; if (dec.neg && dec.fill == '0') { // If filling with '0', ++writer; // ignore the sign we just added add_sign_again = true; // and re-add the sign later. } writer -= fillers; std::fill_n(writer, fillers, dec.fill); if (add_sign_again) *--writer = '-'; } sink.Append(absl::string_view(writer, static_cast(end - writer))); } }; // ----------------------------------------------------------------------------- // AlphaNum // ----------------------------------------------------------------------------- // // The `AlphaNum` class acts as the main parameter type for `StrCat()` and // `StrAppend()`, providing efficient conversion of numeric, boolean, decimal, // and hexadecimal values (through the `Dec` and `Hex` types) into strings. // `AlphaNum` should only be used as a function parameter. Do not instantiate // `AlphaNum` directly as a stack variable. class AlphaNum { public: // No bool ctor -- bools convert to an integral type. // A bool ctor would also convert incoming pointers (bletch). AlphaNum(int x) // NOLINT(runtime/explicit) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(unsigned int x) // NOLINT(runtime/explicit) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(long x) // NOLINT(*) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(unsigned long x) // NOLINT(*) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(long long x) // NOLINT(*) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(unsigned long long x) // NOLINT(*) : piece_(digits_, static_cast( numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0])) {} AlphaNum(float f) // NOLINT(runtime/explicit) : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} AlphaNum(double f) // NOLINT(runtime/explicit) : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} template AlphaNum( // NOLINT(runtime/explicit) const strings_internal::AlphaNumBuffer& buf ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(&buf.data[0], buf.size) {} AlphaNum(const char* c_str // NOLINT(runtime/explicit) ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(NullSafeStringView(c_str)) {} AlphaNum(absl::string_view pc // NOLINT(runtime/explicit) ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(pc) {} template ::value>::type> AlphaNum( // NOLINT(runtime/explicit) const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND, strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {}) : piece_(strings_internal::ExtractStringification(sink, v)) {} template AlphaNum( // NOLINT(runtime/explicit) const std::basic_string, Allocator>& str ABSL_ATTRIBUTE_LIFETIME_BOUND) : piece_(str) {} // Use string literals ":" instead of character literals ':'. AlphaNum(char c) = delete; // NOLINT(runtime/explicit) AlphaNum(const AlphaNum&) = delete; AlphaNum& operator=(const AlphaNum&) = delete; absl::string_view::size_type size() const { return piece_.size(); } const char* data() const { return piece_.data(); } absl::string_view Piece() const { return piece_; } // Match unscoped enums. Use integral promotion so that a `char`-backed // enum becomes a wider integral type AlphaNum will accept. template {} && std::is_convertible{} && !strings_internal::HasAbslStringify::value>::type> AlphaNum(T e) // NOLINT(runtime/explicit) : AlphaNum(+e) {} // This overload matches scoped enums. We must explicitly cast to the // underlying type, but use integral promotion for the same reason as above. template {} && !std::is_convertible{} && !strings_internal::HasAbslStringify::value, char*>::type = nullptr> AlphaNum(T e) // NOLINT(runtime/explicit) : AlphaNum(+static_cast::type>(e)) {} // vector::reference and const_reference require special help to // convert to `AlphaNum` because it requires two user defined conversions. template < typename T, typename std::enable_if< std::is_class::value && (std::is_same::reference>::value || std::is_same::const_reference>::value)>::type* = nullptr> AlphaNum(T e) : AlphaNum(static_cast(e)) {} // NOLINT(runtime/explicit) private: absl::string_view piece_; char digits_[numbers_internal::kFastToBufferSize]; }; // ----------------------------------------------------------------------------- // StrCat() // ----------------------------------------------------------------------------- // // Merges given strings or numbers, using no delimiter(s), returning the merged // result as a string. // // `StrCat()` is designed to be the fastest possible way to construct a string // out of a mix of raw C strings, string_views, strings, bool values, // and numeric values. // // Don't use `StrCat()` for user-visible strings. The localization process // works poorly on strings built up out of fragments. // // For clarity and performance, don't use `StrCat()` when appending to a // string. Use `StrAppend()` instead. In particular, avoid using any of these // (anti-)patterns: // // str.append(StrCat(...)) // str += StrCat(...) // str = StrCat(str, ...) // // The last case is the worst, with a potential to change a loop // from a linear time operation with O(1) dynamic allocations into a // quadratic time operation with O(n) dynamic allocations. // // See `StrAppend()` below for more information. namespace strings_internal { // Do not call directly - this is not part of the public API. std::string CatPieces(std::initializer_list pieces); void AppendPieces(std::string* dest, std::initializer_list pieces); } // namespace strings_internal ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { return std::string(a.data(), a.size()); } ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c); ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template ABSL_MUST_USE_RESULT inline std::string StrCat( const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { return strings_internal::CatPieces( {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), static_cast(args).Piece()...}); } // ----------------------------------------------------------------------------- // StrAppend() // ----------------------------------------------------------------------------- // // Appends a string or set of strings to an existing string, in a similar // fashion to `StrCat()`. // // WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the // a, b, c, parameters be a reference into str. For speed, `StrAppend()` does // not try to check each of its input arguments to be sure that they are not // a subset of the string being appended to. That is, while this will work: // // std::string s = "foo"; // s += s; // // This output is undefined: // // std::string s = "foo"; // StrAppend(&s, s); // // This output is undefined as well, since `absl::string_view` does not own its // data: // // std::string s = "foobar"; // absl::string_view p = s; // StrAppend(&s, p); inline void StrAppend(std::string*) {} void StrAppend(std::string* dest, const AlphaNum& a); void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b); void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c); void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { strings_internal::AppendPieces( dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), static_cast(args).Piece()...}); } // Helper function for the future StrCat default floating-point format, %.6g // This is fast. inline strings_internal::AlphaNumBuffer< numbers_internal::kSixDigitsToBufferSize> SixDigits(double d) { strings_internal::AlphaNumBuffer result; result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); return result; } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_CAT_H_ s2/tools/vendor/abseil-cpp/absl/strings/BUILD.bazel0000644000175000017510000010005614737212474021712 0ustar nileshnilesh# # Copyright 2017 The Abseil Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. load( "//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS", ) package( default_visibility = ["//visibility:public"], features = ["parse_headers"], ) licenses(["notice"]) cc_library( name = "string_view", srcs = ["string_view.cc"], hdrs = ["string_view.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:throw_delegate", ], ) cc_library( name = "strings", srcs = [ "ascii.cc", "charconv.cc", "escaping.cc", "internal/charconv_bigint.cc", "internal/charconv_bigint.h", "internal/charconv_parse.cc", "internal/charconv_parse.h", "internal/damerau_levenshtein_distance.cc", "internal/memutil.cc", "internal/memutil.h", "internal/stl_type_traits.h", "internal/str_join_internal.h", "internal/str_split_internal.h", "internal/stringify_sink.cc", "internal/stringify_sink.h", "match.cc", "numbers.cc", "str_cat.cc", "str_replace.cc", "str_split.cc", "substitute.cc", ], hdrs = [ "ascii.h", "charconv.h", "escaping.h", "internal/damerau_levenshtein_distance.h", "internal/has_absl_stringify.h", "internal/string_constant.h", "match.h", "numbers.h", "str_cat.h", "str_join.h", "str_replace.h", "str_split.h", "string_view.h", "strip.h", "substitute.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, textual_hdrs = [ # string_view.h was once part of :strings, so string_view.h is # re-exported for backwards compatibility. # New code should directly depend on :string_view. "string_view.h", ], deps = [ ":internal", ":string_view", "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/base:raw_logging_internal", "//absl/base:throw_delegate", "//absl/memory", "//absl/meta:type_traits", "//absl/numeric:bits", "//absl/numeric:int128", ], ) cc_library( name = "internal", srcs = [ "internal/escaping.cc", "internal/ostringstream.cc", "internal/utf8.cc", ], hdrs = [ "internal/char_map.h", "internal/escaping.h", "internal/ostringstream.h", "internal/resize_uninitialized.h", "internal/utf8.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/base:raw_logging_internal", "//absl/meta:type_traits", ], ) cc_test( name = "match_test", size = "small", srcs = ["match_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "escaping_test", size = "small", srcs = [ "escaping_test.cc", "internal/escaping_test_common.h", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":strings", "//absl/base:core_headers", "//absl/container:fixed_array", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "escaping_benchmark", srcs = [ "escaping_benchmark.cc", "internal/escaping_test_common.h", ], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:raw_logging_internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "ascii_test", size = "small", srcs = ["ascii_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "ascii_benchmark", srcs = ["ascii_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "damerau_levenshtein_distance_test", size = "small", srcs = [ "internal/damerau_levenshtein_distance_test.cc", ], copts = ABSL_TEST_COPTS, deps = [ "//absl/strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "memutil_benchmark", srcs = [ "internal/memutil.h", "internal/memutil_benchmark.cc", ], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "memutil_test", size = "small", srcs = [ "internal/memutil.h", "internal/memutil_test.cc", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "utf8_test", size = "small", srcs = [ "internal/utf8_test.cc", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":internal", "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "string_constant_test", size = "small", srcs = ["internal/string_constant_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/meta:type_traits", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "string_view_benchmark", srcs = ["string_view_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":string_view", ":strings", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "string_view_test", size = "small", srcs = ["string_view_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":string_view", "//absl/base:config", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "cord_internal", srcs = [ "internal/cord_internal.cc", "internal/cord_rep_btree.cc", "internal/cord_rep_btree_navigator.cc", "internal/cord_rep_btree_reader.cc", "internal/cord_rep_consume.cc", "internal/cord_rep_crc.cc", "internal/cord_rep_ring.cc", ], hdrs = [ "internal/cord_data_edge.h", "internal/cord_internal.h", "internal/cord_rep_btree.h", "internal/cord_rep_btree_navigator.h", "internal/cord_rep_btree_reader.h", "internal/cord_rep_consume.h", "internal/cord_rep_crc.h", "internal/cord_rep_flat.h", "internal/cord_rep_ring.h", "internal/cord_rep_ring_reader.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//visibility:private", ], deps = [ ":strings", "//absl/base:base_internal", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/base:raw_logging_internal", "//absl/base:throw_delegate", "//absl/container:compressed_tuple", "//absl/container:container_memory", "//absl/container:inlined_vector", "//absl/container:layout", "//absl/crc:crc_cord_state", "//absl/functional:function_ref", "//absl/meta:type_traits", "//absl/types:span", ], ) cc_test( name = "cord_data_edge_test", size = "small", srcs = ["internal/cord_data_edge_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":cord_rep_test_util", ":strings", "//absl/base:config", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_rep_btree_test", size = "medium", timeout = "long", srcs = ["internal/cord_rep_btree_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":cord_rep_test_util", ":strings", "//absl/base:config", "//absl/base:raw_logging_internal", "//absl/cleanup", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_rep_btree_navigator_test", size = "medium", srcs = ["internal/cord_rep_btree_navigator_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":cord_rep_test_util", ":strings", "//absl/base:config", "//absl/base:raw_logging_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_rep_btree_reader_test", size = "medium", srcs = ["internal/cord_rep_btree_reader_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":cord_internal", ":cord_rep_test_util", ":strings", "//absl/base:config", "//absl/base:raw_logging_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_rep_crc_test", size = "small", srcs = ["internal/cord_rep_crc_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":cord_rep_test_util", "//absl/base:config", "//absl/crc:crc_cord_state", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "cordz_update_tracker", hdrs = ["internal/cordz_update_tracker.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = ["//absl/base:config"], ) cc_test( name = "cordz_update_tracker_test", srcs = ["internal/cordz_update_tracker_test.cc"], deps = [ ":cordz_update_tracker", "//absl/base:config", "//absl/base:core_headers", "//absl/synchronization", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "cord", srcs = [ "cord.cc", "cord_analysis.cc", "cord_analysis.h", "cord_buffer.cc", ], hdrs = [ "cord.h", "cord_buffer.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord_internal", ":cordz_functions", ":cordz_info", ":cordz_statistics", ":cordz_update_scope", ":cordz_update_tracker", ":internal", ":strings", "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/base:raw_logging_internal", "//absl/container:fixed_array", "//absl/container:inlined_vector", "//absl/crc:crc_cord_state", "//absl/functional:function_ref", "//absl/meta:type_traits", "//absl/numeric:bits", "//absl/types:optional", "//absl/types:span", ], ) cc_library( name = "cordz_handle", srcs = ["internal/cordz_handle.cc"], hdrs = ["internal/cordz_handle.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ "//absl/base", "//absl/base:config", "//absl/base:raw_logging_internal", "//absl/synchronization", ], ) cc_library( name = "cordz_info", srcs = ["internal/cordz_info.cc"], hdrs = ["internal/cordz_info.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ ":cord_internal", ":cordz_functions", ":cordz_handle", ":cordz_statistics", ":cordz_update_tracker", "//absl/base", "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/container:inlined_vector", "//absl/debugging:stacktrace", "//absl/synchronization", "//absl/time", "//absl/types:span", ], ) cc_library( name = "cordz_update_scope", hdrs = ["internal/cordz_update_scope.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ ":cord_internal", ":cordz_info", ":cordz_update_tracker", "//absl/base:config", "//absl/base:core_headers", ], ) cc_test( name = "cordz_update_scope_test", srcs = ["internal/cordz_update_scope_test.cc"], copts = ABSL_DEFAULT_COPTS, deps = [ ":cord_internal", ":cordz_info", ":cordz_test_helpers", ":cordz_update_scope", ":cordz_update_tracker", "//absl/base:config", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "cordz_sample_token", srcs = ["internal/cordz_sample_token.cc"], hdrs = ["internal/cordz_sample_token.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ ":cordz_handle", ":cordz_info", "//absl/base:config", ], ) cc_library( name = "cordz_functions", srcs = ["internal/cordz_functions.cc"], hdrs = ["internal/cordz_functions.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/profiling:exponential_biased", ], ) cc_library( name = "cordz_statistics", hdrs = ["internal/cordz_statistics.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ ":cordz_update_tracker", "//absl/base:config", ], ) cc_test( name = "cordz_functions_test", srcs = [ "internal/cordz_functions_test.cc", ], deps = [ ":cordz_functions", ":cordz_test_helpers", "//absl/base:config", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cordz_handle_test", srcs = [ "internal/cordz_handle_test.cc", ], deps = [ ":cordz_handle", "//absl/base:config", "//absl/memory", "//absl/random", "//absl/random:distributions", "//absl/synchronization", "//absl/synchronization:thread_pool", "//absl/time", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cordz_info_test", srcs = [ "internal/cordz_info_test.cc", ], deps = [ ":cord_internal", ":cordz_handle", ":cordz_info", ":cordz_statistics", ":cordz_test_helpers", ":cordz_update_tracker", ":strings", "//absl/base:config", "//absl/debugging:stacktrace", "//absl/debugging:symbolize", "//absl/types:span", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cordz_info_statistics_test", srcs = [ "internal/cordz_info_statistics_test.cc", ], deps = [ ":cord", ":cord_internal", ":cordz_info", ":cordz_sample_token", ":cordz_statistics", ":cordz_update_scope", ":cordz_update_tracker", "//absl/base:config", "//absl/crc:crc_cord_state", "//absl/synchronization", "//absl/synchronization:thread_pool", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cordz_sample_token_test", srcs = [ "internal/cordz_sample_token_test.cc", ], deps = [ ":cord_internal", ":cordz_handle", ":cordz_info", ":cordz_sample_token", ":cordz_test_helpers", "//absl/base:config", "//absl/memory", "//absl/random", "//absl/synchronization", "//absl/synchronization:thread_pool", "//absl/time", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "cord_test_helpers", testonly = 1, hdrs = [ "cord_test_helpers.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord", ":cord_internal", ":strings", "//absl/base:config", ], ) cc_library( name = "cord_rep_test_util", testonly = 1, hdrs = ["internal/cord_rep_test_util.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord_internal", ":strings", "//absl/base:config", "//absl/base:raw_logging_internal", ], ) cc_library( name = "cordz_test_helpers", testonly = 1, hdrs = ["cordz_test_helpers.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":cord", ":cord_internal", ":cordz_info", ":cordz_sample_token", ":cordz_statistics", ":cordz_update_tracker", ":strings", "//absl/base:config", "//absl/base:core_headers", "@com_google_googletest//:gtest", ], ) cc_test( name = "cord_buffer_test", size = "small", srcs = ["cord_buffer_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":cord_internal", ":cord_rep_test_util", "//absl/base:config", "//absl/types:span", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_test", size = "medium", srcs = ["cord_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":cord_test_helpers", ":cordz_functions", ":cordz_test_helpers", ":str_format", ":strings", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/container:fixed_array", "//absl/hash", "//absl/log", "//absl/log:check", "//absl/random", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cordz_test", size = "medium", srcs = ["cordz_test.cc"], copts = ABSL_TEST_COPTS, tags = [ "benchmark", "no_test_android_arm", "no_test_android_arm64", "no_test_android_x86", "no_test_ios_x86_64", "no_test_lexan", "no_test_loonix", ], visibility = ["//visibility:private"], deps = [ ":cord", ":cord_test_helpers", ":cordz_functions", ":cordz_info", ":cordz_sample_token", ":cordz_statistics", ":cordz_test_helpers", ":cordz_update_tracker", ":strings", "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_ring_test", size = "medium", srcs = ["cord_ring_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":strings", "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/debugging:leak_check", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "cord_ring_reader_test", size = "medium", srcs = ["cord_ring_reader_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord_internal", ":strings", "//absl/base:core_headers", "//absl/debugging:leak_check", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "substitute_test", size = "small", srcs = ["substitute_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_replace_benchmark", srcs = ["str_replace_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:raw_logging_internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "str_replace_test", size = "small", srcs = ["str_replace_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_split_test", srcs = ["str_split_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/container:btree", "//absl/container:flat_hash_map", "//absl/container:node_hash_map", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_split_benchmark", srcs = ["str_split_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:raw_logging_internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "ostringstream_test", size = "small", srcs = ["internal/ostringstream_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "ostringstream_benchmark", srcs = ["internal/ostringstream_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "resize_uninitialized_test", size = "small", srcs = [ "internal/resize_uninitialized.h", "internal/resize_uninitialized_test.cc", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ "//absl/base:core_headers", "//absl/meta:type_traits", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_join_test", size = "small", srcs = ["str_join_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:core_headers", "//absl/memory", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_join_benchmark", srcs = ["str_join_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "str_cat_test", size = "small", srcs = ["str_cat_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format", ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_cat_benchmark", srcs = ["str_cat_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "numbers_test", size = "medium", srcs = [ "internal/numbers_test_common.h", "numbers_test.cc", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":internal", ":pow10_helper", ":strings", "//absl/base:config", "//absl/log", "//absl/random", "//absl/random:distributions", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "numbers_benchmark", srcs = ["numbers_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:raw_logging_internal", "//absl/random", "//absl/random:distributions", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "strip_test", size = "small", srcs = ["strip_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "char_map_test", srcs = ["internal/char_map_test.cc"], copts = ABSL_TEST_COPTS, deps = [ ":internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "char_map_benchmark", srcs = ["internal/char_map_benchmark.cc"], copts = ABSL_TEST_COPTS, tags = ["benchmark"], deps = [ ":internal", "@com_github_google_benchmark//:benchmark_main", ], ) cc_test( name = "charconv_test", srcs = ["charconv_test.cc"], copts = ABSL_TEST_COPTS, deps = [ ":pow10_helper", ":str_format", ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "charconv_parse_test", srcs = [ "internal/charconv_parse.h", "internal/charconv_parse_test.cc", ], copts = ABSL_TEST_COPTS, deps = [ ":strings", "//absl/base:config", "//absl/log:check", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "charconv_bigint_test", srcs = [ "internal/charconv_bigint.h", "internal/charconv_bigint_test.cc", "internal/charconv_parse.h", ], copts = ABSL_TEST_COPTS, deps = [ ":strings", "//absl/base:config", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "charconv_benchmark", srcs = [ "charconv_benchmark.cc", ], tags = [ "benchmark", ], deps = [ ":strings", "@com_github_google_benchmark//:benchmark_main", ], ) cc_library( name = "str_format", hdrs = [ "str_format.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":str_format_internal", ], ) cc_library( name = "str_format_internal", srcs = [ "internal/str_format/arg.cc", "internal/str_format/bind.cc", "internal/str_format/extension.cc", "internal/str_format/float_conversion.cc", "internal/str_format/output.cc", "internal/str_format/parser.cc", ], hdrs = [ "internal/str_format/arg.h", "internal/str_format/bind.h", "internal/str_format/checker.h", "internal/str_format/constexpr_parser.h", "internal/str_format/extension.h", "internal/str_format/float_conversion.h", "internal/str_format/output.h", "internal/str_format/parser.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":strings", "//absl/base:config", "//absl/base:core_headers", "//absl/container:inlined_vector", "//absl/functional:function_ref", "//absl/meta:type_traits", "//absl/numeric:bits", "//absl/numeric:int128", "//absl/numeric:representation", "//absl/types:optional", "//absl/types:span", "//absl/utility", ], ) cc_test( name = "str_format_test", srcs = ["str_format_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":str_format", ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_extension_test", srcs = [ "internal/str_format/extension_test.cc", ], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format", ":str_format_internal", ":strings", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_arg_test", srcs = ["internal/str_format/arg_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format", ":str_format_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_bind_test", srcs = ["internal/str_format/bind_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_checker_test", srcs = ["internal/str_format/checker_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_convert_test", size = "medium", srcs = ["internal/str_format/convert_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format_internal", ":strings", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/log", "//absl/types:optional", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_output_test", srcs = ["internal/str_format/output_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":cord", ":str_format_internal", "@com_google_googletest//:gtest_main", ], ) cc_test( name = "str_format_parser_test", srcs = ["internal/str_format/parser_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":str_format_internal", "//absl/base:core_headers", "@com_google_googletest//:gtest_main", ], ) cc_library( name = "pow10_helper", testonly = True, srcs = ["internal/pow10_helper.cc"], hdrs = ["internal/pow10_helper.h"], linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = ["//absl/base:config"], ) cc_test( name = "pow10_helper_test", srcs = ["internal/pow10_helper_test.cc"], copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ ":pow10_helper", ":str_format", "@com_google_googletest//:gtest_main", ], ) cc_binary( name = "atod_manual_test", testonly = 1, srcs = ["atod_manual_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = ["//visibility:private"], deps = [ ":str_format", ":strings", "//absl/base", "//absl/types:optional", ], ) cc_test( name = "char_formatting_test", srcs = [ "char_formatting_test.cc", ], deps = [ ":str_format", ":strings", "@com_google_googletest//:gtest_main", ], ) s2/tools/vendor/abseil-cpp/absl/strings/str_format.h0000644000175000017510000010537114737212474022372 0ustar nileshnilesh// // Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: str_format.h // ----------------------------------------------------------------------------- // // The `str_format` library is a typesafe replacement for the family of // `printf()` string formatting routines within the `` standard library // header. Like the `printf` family, `str_format` uses a "format string" to // perform argument substitutions based on types. See the `FormatSpec` section // below for format string documentation. // // Example: // // std::string s = absl::StrFormat( // "%s %s You have $%d!", "Hello", name, dollars); // // The library consists of the following basic utilities: // // * `absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to // write a format string to a `string` value. // * `absl::StrAppendFormat()` to append a format string to a `string` // * `absl::StreamFormat()` to more efficiently write a format string to a // stream, such as`std::cout`. // * `absl::PrintF()`, `absl::FPrintF()` and `absl::SNPrintF()` as // drop-in replacements for `std::printf()`, `std::fprintf()` and // `std::snprintf()`. // // Note: An `absl::SPrintF()` drop-in replacement is not supported as it // is generally unsafe due to buffer overflows. Use `absl::StrFormat` which // returns the string as output instead of expecting a pre-allocated buffer. // // Additionally, you can provide a format string (and its associated arguments) // using one of the following abstractions: // // * A `FormatSpec` class template fully encapsulates a format string and its // type arguments and is usually provided to `str_format` functions as a // variadic argument of type `FormatSpec`. The `FormatSpec` // template is evaluated at compile-time, providing type safety. // * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled // format string for a specific set of type(s), and which can be passed // between API boundaries. (The `FormatSpec` type should not be used // directly except as an argument type for wrapper functions.) // // The `str_format` library provides the ability to output its format strings to // arbitrary sink types: // // * A generic `Format()` function to write outputs to arbitrary sink types, // which must implement a `FormatRawSink` interface. // // * A `FormatUntyped()` function that is similar to `Format()` except it is // loosely typed. `FormatUntyped()` is not a template and does not perform // any compile-time checking of the format string; instead, it returns a // boolean from a runtime check. // // In addition, the `str_format` library provides extension points for // augmenting formatting to new types. See "StrFormat Extensions" below. #ifndef ABSL_STRINGS_STR_FORMAT_H_ #define ABSL_STRINGS_STR_FORMAT_H_ #include #include #include "absl/strings/internal/str_format/arg.h" // IWYU pragma: export #include "absl/strings/internal/str_format/bind.h" // IWYU pragma: export #include "absl/strings/internal/str_format/checker.h" // IWYU pragma: export #include "absl/strings/internal/str_format/extension.h" // IWYU pragma: export #include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export namespace absl { ABSL_NAMESPACE_BEGIN // UntypedFormatSpec // // A type-erased class that can be used directly within untyped API entry // points. An `UntypedFormatSpec` is specifically used as an argument to // `FormatUntyped()`. // // Example: // // absl::UntypedFormatSpec format("%d"); // std::string out; // CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)})); class UntypedFormatSpec { public: UntypedFormatSpec() = delete; UntypedFormatSpec(const UntypedFormatSpec&) = delete; UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete; explicit UntypedFormatSpec(string_view s) : spec_(s) {} protected: explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc) : spec_(pc) {} private: friend str_format_internal::UntypedFormatSpecImpl; str_format_internal::UntypedFormatSpecImpl spec_; }; // FormatStreamed() // // Takes a streamable argument and returns an object that can print it // with '%s'. Allows printing of types that have an `operator<<` but no // intrinsic type support within `StrFormat()` itself. // // Example: // // absl::StrFormat("%s", absl::FormatStreamed(obj)); template str_format_internal::StreamedWrapper FormatStreamed(const T& v) { return str_format_internal::StreamedWrapper(v); } // FormatCountCapture // // This class provides a way to safely wrap `StrFormat()` captures of `%n` // conversions, which denote the number of characters written by a formatting // operation to this point, into an integer value. // // This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in // the `printf()` family of functions, `%n` is not safe to use, as the `int *` // buffer can be used to capture arbitrary data. // // Example: // // int n = 0; // std::string s = absl::StrFormat("%s%d%n", "hello", 123, // absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); class FormatCountCapture { public: explicit FormatCountCapture(int* p) : p_(p) {} private: // FormatCountCaptureHelper is used to define FormatConvertImpl() for this // class. friend struct str_format_internal::FormatCountCaptureHelper; // Unused() is here because of the false positive from -Wunused-private-field // p_ is used in the templated function of the friend FormatCountCaptureHelper // class. int* Unused() { return p_; } int* p_; }; // FormatSpec // // The `FormatSpec` type defines the makeup of a format string within the // `str_format` library. It is a variadic class template that is evaluated at // compile-time, according to the format string and arguments that are passed to // it. // // You should not need to manipulate this type directly. You should only name it // if you are writing wrapper functions which accept format arguments that will // be provided unmodified to functions in this library. Such a wrapper function // might be a class method that provides format arguments and/or internally uses // the result of formatting. // // For a `FormatSpec` to be valid at compile-time, it must be provided as // either: // // * A `constexpr` literal or `absl::string_view`, which is how it most often // used. // * A `ParsedFormat` instantiation, which ensures the format string is // valid before use. (See below.) // // Example: // // // Provided as a string literal. // absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6); // // // Provided as a constexpr absl::string_view. // constexpr absl::string_view formatString = "Welcome to %s, Number %d!"; // absl::StrFormat(formatString, "The Village", 6); // // // Provided as a pre-compiled ParsedFormat object. // // Note that this example is useful only for illustration purposes. // absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); // absl::StrFormat(formatString, "TheVillage", 6); // // A format string generally follows the POSIX syntax as used within the POSIX // `printf` specification. (Exceptions are noted below.) // // (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html) // // In specific, the `FormatSpec` supports the following type specifiers: // * `c` for characters // * `s` for strings // * `d` or `i` for integers // * `o` for unsigned integer conversions into octal // * `x` or `X` for unsigned integer conversions into hex // * `u` for unsigned integers // * `f` or `F` for floating point values into decimal notation // * `e` or `E` for floating point values into exponential notation // * `a` or `A` for floating point values into hex exponential notation // * `g` or `G` for floating point values into decimal or exponential // notation based on their precision // * `p` for pointer address values // * `n` for the special case of writing out the number of characters // written to this point. The resulting value must be captured within an // `absl::FormatCountCapture` type. // * `v` for values using the default format for a deduced type. These deduced // types include many of the primitive types denoted here as well as // user-defined types containing the proper extensions. (See below for more // information.) // // Implementation-defined behavior: // * A null pointer provided to "%s" or "%p" is output as "(nil)". // * A non-null pointer provided to "%p" is output in hex as if by %#x or // %#lx. // // NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned // counterpart before formatting. // // Examples: // "%c", 'a' -> "a" // "%c", 32 -> " " // "%s", "C" -> "C" // "%s", std::string("C++") -> "C++" // "%d", -10 -> "-10" // "%o", 10 -> "12" // "%x", 16 -> "10" // "%f", 123456789 -> "123456789.000000" // "%e", .01 -> "1.00000e-2" // "%a", -3.0 -> "-0x1.8p+1" // "%g", .01 -> "1e-2" // "%p", (void*)&value -> "0x7ffdeb6ad2a4" // // int n = 0; // std::string s = absl::StrFormat( // "%s%d%n", "hello", 123, absl::FormatCountCapture(&n)); // EXPECT_EQ(8, n); // // NOTE: the `v` specifier (for "value") is a type specifier not present in the // POSIX specification. %v will format values according to their deduced type. // `v` uses `d` for signed integer values, `u` for unsigned integer values, `g` // for floating point values, and formats boolean values as "true"/"false" // (instead of 1 or 0 for booleans formatted using d). `const char*` is not // supported; please use `std:string` and `string_view`. `char` is also not // supported due to ambiguity of the type. This specifier does not support // modifiers. // // The `FormatSpec` intrinsically supports all of these fundamental C++ types: // // * Characters: `char`, `signed char`, `unsigned char` // * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, // `unsigned long`, `long long`, `unsigned long long` // * Enums: printed as their underlying integral value // * Floating-point: `float`, `double`, `long double` // // However, in the `str_format` library, a format conversion specifies a broader // C++ conceptual category instead of an exact type. For example, `%s` binds to // any string-like argument, so `std::string`, `absl::string_view`, and // `const char*` are all accepted. Likewise, `%d` accepts any integer-like // argument, etc. template using FormatSpec = str_format_internal::FormatSpecTemplate< str_format_internal::ArgumentToConv()...>; // ParsedFormat // // A `ParsedFormat` is a class template representing a preparsed `FormatSpec`, // with template arguments specifying the conversion characters used within the // format string. Such characters must be valid format type specifiers, and // these type specifiers are checked at compile-time. // // Instances of `ParsedFormat` can be created, copied, and reused to speed up // formatting loops. A `ParsedFormat` may either be constructed statically, or // dynamically through its `New()` factory function, which only constructs a // runtime object if the format is valid at that time. // // Example: // // // Verified at compile time. // absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); // absl::StrFormat(formatString, "TheVillage", 6); // // // Verified at runtime. // auto format_runtime = absl::ParsedFormat<'d'>::New(format_string); // if (format_runtime) { // value = absl::StrFormat(*format_runtime, i); // } else { // ... error case ... // } #if defined(__cpp_nontype_template_parameter_auto) // If C++17 is available, an 'extended' format is also allowed that can specify // multiple conversion characters per format argument, using a combination of // `absl::FormatConversionCharSet` enum values (logically a set union) // via the `|` operator. (Single character-based arguments are still accepted, // but cannot be combined). Some common conversions also have predefined enum // values, such as `absl::FormatConversionCharSet::kIntegral`. // // Example: // // Extended format supports multiple conversion characters per argument, // // specified via a combination of `FormatConversionCharSet` enums. // using MyFormat = absl::ParsedFormat; // MyFormat GetFormat(bool use_hex) { // if (use_hex) return MyFormat("foo %x bar"); // return MyFormat("foo %d bar"); // } // // `format` can be used with any value that supports 'd' and 'x', // // like `int`. // auto format = GetFormat(use_hex); // value = StringF(format, i); template using ParsedFormat = absl::str_format_internal::ExtendedParsedFormat< absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; #else template using ParsedFormat = str_format_internal::ExtendedParsedFormat< absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; #endif // defined(__cpp_nontype_template_parameter_auto) // StrFormat() // // Returns a `string` given a `printf()`-style format string and zero or more // additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the // primary formatting function within the `str_format` library, and should be // used in most cases where you need type-safe conversion of types into // formatted strings. // // The format string generally consists of ordinary character data along with // one or more format conversion specifiers (denoted by the `%` character). // Ordinary character data is returned unchanged into the result string, while // each conversion specification performs a type substitution from // `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full // information on the makeup of this format string. // // Example: // // std::string s = absl::StrFormat( // "Welcome to %s, Number %d!", "The Village", 6); // EXPECT_EQ("Welcome to The Village, Number 6!", s); // // Returns an empty string in case of error. template ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec& format, const Args&... args) { return str_format_internal::FormatPack( str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // StrAppendFormat() // // Appends to a `dst` string given a format string, and zero or more additional // arguments, returning `*dst` as a convenience for chaining purposes. Appends // nothing in case of error (but possibly alters its capacity). // // Example: // // std::string orig("For example PI is approximately "); // std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); template std::string& StrAppendFormat(std::string* dst, const FormatSpec& format, const Args&... args) { return str_format_internal::AppendPack( dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // StreamFormat() // // Writes to an output stream given a format string and zero or more arguments, // generally in a manner that is more efficient than streaming the result of // `absl:: StrFormat()`. The returned object must be streamed before the full // expression ends. // // Example: // // std::cout << StreamFormat("%12.6f", 3.14); template ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat( const FormatSpec& format, const Args&... args) { return str_format_internal::Streamable( str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // PrintF() // // Writes to stdout given a format string and zero or more arguments. This // function is functionally equivalent to `std::printf()` (and type-safe); // prefer `absl::PrintF()` over `std::printf()`. // // Example: // // std::string_view s = "Ulaanbaatar"; // absl::PrintF("The capital of Mongolia is %s", s); // // Outputs: "The capital of Mongolia is Ulaanbaatar" // template int PrintF(const FormatSpec& format, const Args&... args) { return str_format_internal::FprintF( stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // FPrintF() // // Writes to a file given a format string and zero or more arguments. This // function is functionally equivalent to `std::fprintf()` (and type-safe); // prefer `absl::FPrintF()` over `std::fprintf()`. // // Example: // // std::string_view s = "Ulaanbaatar"; // absl::FPrintF(stdout, "The capital of Mongolia is %s", s); // // Outputs: "The capital of Mongolia is Ulaanbaatar" // template int FPrintF(std::FILE* output, const FormatSpec& format, const Args&... args) { return str_format_internal::FprintF( output, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // SNPrintF() // // Writes to a sized buffer given a format string and zero or more arguments. // This function is functionally equivalent to `std::snprintf()` (and // type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`. // // In particular, a successful call to `absl::SNPrintF()` writes at most `size` // bytes of the formatted output to `output`, including a NUL-terminator, and // returns the number of bytes that would have been written if truncation did // not occur. In the event of an error, a negative value is returned and `errno` // is set. // // Example: // // std::string_view s = "Ulaanbaatar"; // char output[128]; // absl::SNPrintF(output, sizeof(output), // "The capital of Mongolia is %s", s); // // Post-condition: output == "The capital of Mongolia is Ulaanbaatar" // template int SNPrintF(char* output, std::size_t size, const FormatSpec& format, const Args&... args) { return str_format_internal::SnprintF( output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // ----------------------------------------------------------------------------- // Custom Output Formatting Functions // ----------------------------------------------------------------------------- // FormatRawSink // // FormatRawSink is a type erased wrapper around arbitrary sink objects // specifically used as an argument to `Format()`. // // All the object has to do define an overload of `AbslFormatFlush()` for the // sink, usually by adding a ADL-based free function in the same namespace as // the sink: // // void AbslFormatFlush(MySink* dest, absl::string_view part); // // where `dest` is the pointer passed to `absl::Format()`. The function should // append `part` to `dest`. // // FormatRawSink does not own the passed sink object. The passed object must // outlive the FormatRawSink. class FormatRawSink { public: // Implicitly convert from any type that provides the hook function as // described above. template ::value>::type> FormatRawSink(T* raw) // NOLINT : sink_(raw) {} private: friend str_format_internal::FormatRawSinkImpl; str_format_internal::FormatRawSinkImpl sink_; }; // Format() // // Writes a formatted string to an arbitrary sink object (implementing the // `absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // // By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as // destination objects. If a `std::string` is used the formatted string is // appended to it. // // `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for // custom sinks. The format string, like format strings for `StrFormat()`, is // checked at compile-time. // // On failure, this function returns `false` and the state of the sink is // unspecified. template bool Format(FormatRawSink raw_sink, const FormatSpec& format, const Args&... args) { return str_format_internal::FormatUntyped( str_format_internal::FormatRawSinkImpl::Extract(raw_sink), str_format_internal::UntypedFormatSpecImpl::Extract(format), {str_format_internal::FormatArgImpl(args)...}); } // FormatArg // // A type-erased handle to a format argument specifically used as an argument to // `FormatUntyped()`. You may construct `FormatArg` by passing // reference-to-const of any printable type. `FormatArg` is both copyable and // assignable. The source data must outlive the `FormatArg` instance. See // example below. // using FormatArg = str_format_internal::FormatArgImpl; // FormatUntyped() // // Writes a formatted string to an arbitrary sink object (implementing the // `absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or // more additional arguments. // // This function acts as the most generic formatting function in the // `str_format` library. The caller provides a raw sink, an unchecked format // string, and (usually) a runtime specified list of arguments; no compile-time // checking of formatting is performed within this function. As a result, a // caller should check the return value to verify that no error occurred. // On failure, this function returns `false` and the state of the sink is // unspecified. // // The arguments are provided in an `absl::Span`. // Each `absl::FormatArg` object binds to a single argument and keeps a // reference to it. The values used to create the `FormatArg` objects must // outlive this function call. // // Example: // // std::optional FormatDynamic( // const std::string& in_format, // const vector& in_args) { // std::string out; // std::vector args; // for (const auto& v : in_args) { // // It is important that 'v' is a reference to the objects in in_args. // // The values we pass to FormatArg must outlive the call to // // FormatUntyped. // args.emplace_back(v); // } // absl::UntypedFormatSpec format(in_format); // if (!absl::FormatUntyped(&out, format, args)) { // return std::nullopt; // } // return std::move(out); // } // ABSL_MUST_USE_RESULT inline bool FormatUntyped( FormatRawSink raw_sink, const UntypedFormatSpec& format, absl::Span args) { return str_format_internal::FormatUntyped( str_format_internal::FormatRawSinkImpl::Extract(raw_sink), str_format_internal::UntypedFormatSpecImpl::Extract(format), args); } //------------------------------------------------------------------------------ // StrFormat Extensions //------------------------------------------------------------------------------ // // AbslStringify() // // A simpler customization API for formatting user-defined types using // absl::StrFormat(). The API relies on detecting an overload in the // user-defined type's namespace of a free (non-member) `AbslStringify()` // function as a friend definition with the following signature: // // template // void AbslStringify(Sink& sink, const X& value); // // An `AbslStringify()` overload for a type should only be declared in the same // file and namespace as said type. // // Note that unlike with AbslFormatConvert(), AbslStringify() does not allow // customization of allowed conversion characters. AbslStringify() uses `%v` as // the underlying conversion specififer. Additionally, AbslStringify() supports // use with absl::StrCat while AbslFormatConvert() does not. // // Example: // // struct Point { // // To add formatting support to `Point`, we simply need to add a free // // (non-member) function `AbslStringify()`. This method prints in the // // request format using the underlying `%v` specifier. You can add such a // // free function using a friend declaration within the body of the class. // // The sink parameter is a templated type to avoid requiring dependencies. // template // friend void AbslStringify(Sink& sink, const Point& p) { // absl::Format(&sink, "(%v, %v)", p.x, p.y); // } // // int x; // int y; // }; // // AbslFormatConvert() // // The StrFormat library provides a customization API for formatting // user-defined types using absl::StrFormat(). The API relies on detecting an // overload in the user-defined type's namespace of a free (non-member) // `AbslFormatConvert()` function, usually as a friend definition with the // following signature: // // absl::FormatConvertResult<...> AbslFormatConvert( // const X& value, // const absl::FormatConversionSpec& spec, // absl::FormatSink *sink); // // An `AbslFormatConvert()` overload for a type should only be declared in the // same file and namespace as said type. // // The abstractions within this definition include: // // * An `absl::FormatConversionSpec` to specify the fields to pull from a // user-defined type's format string // * An `absl::FormatSink` to hold the converted string data during the // conversion process. // * An `absl::FormatConvertResult` to hold the status of the returned // formatting operation // // The return type encodes all the conversion characters that your // AbslFormatConvert() routine accepts. The return value should be {true}. // A return value of {false} will result in `StrFormat()` returning // an empty string. This result will be propagated to the result of // `FormatUntyped`. // // Example: // // struct Point { // // To add formatting support to `Point`, we simply need to add a free // // (non-member) function `AbslFormatConvert()`. This method interprets // // `spec` to print in the request format. The allowed conversion characters // // can be restricted via the type of the result, in this example // // string and integral formatting are allowed (but not, for instance // // floating point characters like "%f"). You can add such a free function // // using a friend declaration within the body of the class: // friend absl::FormatConvertResult // AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec, // absl::FormatSink* s) { // if (spec.conversion_char() == absl::FormatConversionChar::s) { // absl::Format(s, "x=%vy=%v", p.x, p.y); // } else { // absl::Format(s, "%v,%v", p.x, p.y); // } // return {true}; // } // // int x; // int y; // }; // clang-format off // FormatConversionChar // // Specifies the formatting character provided in the format string // passed to `StrFormat()`. enum class FormatConversionChar : uint8_t { c, s, // text d, i, o, u, x, X, // int f, F, e, E, g, G, a, A, // float n, p, v // misc }; // clang-format on // FormatConversionSpec // // Specifies modifications to the conversion of the format string, through use // of one or more format flags in the source format string. class FormatConversionSpec { public: // FormatConversionSpec::is_basic() // // Indicates that width and precision are not specified, and no additional // flags are set for this conversion character in the format string. bool is_basic() const { return impl_.is_basic(); } // FormatConversionSpec::has_left_flag() // // Indicates whether the result should be left justified for this conversion // character in the format string. This flag is set through use of a '-' // character in the format string. E.g. "%-s" bool has_left_flag() const { return impl_.has_left_flag(); } // FormatConversionSpec::has_show_pos_flag() // // Indicates whether a sign column is prepended to the result for this // conversion character in the format string, even if the result is positive. // This flag is set through use of a '+' character in the format string. // E.g. "%+d" bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); } // FormatConversionSpec::has_sign_col_flag() // // Indicates whether a mandatory sign column is added to the result for this // conversion character. This flag is set through use of a space character // (' ') in the format string. E.g. "% i" bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); } // FormatConversionSpec::has_alt_flag() // // Indicates whether an "alternate" format is applied to the result for this // conversion character. Alternative forms depend on the type of conversion // character, and unallowed alternatives are undefined. This flag is set // through use of a '#' character in the format string. E.g. "%#h" bool has_alt_flag() const { return impl_.has_alt_flag(); } // FormatConversionSpec::has_zero_flag() // // Indicates whether zeroes should be prepended to the result for this // conversion character instead of spaces. This flag is set through use of the // '0' character in the format string. E.g. "%0f" bool has_zero_flag() const { return impl_.has_zero_flag(); } // FormatConversionSpec::conversion_char() // // Returns the underlying conversion character. FormatConversionChar conversion_char() const { return impl_.conversion_char(); } // FormatConversionSpec::width() // // Returns the specified width (indicated through use of a non-zero integer // value or '*' character) of the conversion character. If width is // unspecified, it returns a negative value. int width() const { return impl_.width(); } // FormatConversionSpec::precision() // // Returns the specified precision (through use of the '.' character followed // by a non-zero integer value or '*' character) of the conversion character. // If precision is unspecified, it returns a negative value. int precision() const { return impl_.precision(); } private: explicit FormatConversionSpec( str_format_internal::FormatConversionSpecImpl impl) : impl_(impl) {} friend str_format_internal::FormatConversionSpecImpl; absl::str_format_internal::FormatConversionSpecImpl impl_; }; // Type safe OR operator for FormatConversionCharSet to allow accepting multiple // conversion chars in custom format converters. constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, FormatConversionCharSet b) { return static_cast(static_cast(a) | static_cast(b)); } // FormatConversionCharSet // // Specifies the _accepted_ conversion types as a template parameter to // FormatConvertResult for custom implementations of `AbslFormatConvert`. // Note the helper predefined alias definitions (kIntegral, etc.) below. enum class FormatConversionCharSet : uint64_t { // text c = str_format_internal::FormatConversionCharToConvInt('c'), s = str_format_internal::FormatConversionCharToConvInt('s'), // integer d = str_format_internal::FormatConversionCharToConvInt('d'), i = str_format_internal::FormatConversionCharToConvInt('i'), o = str_format_internal::FormatConversionCharToConvInt('o'), u = str_format_internal::FormatConversionCharToConvInt('u'), x = str_format_internal::FormatConversionCharToConvInt('x'), X = str_format_internal::FormatConversionCharToConvInt('X'), // Float f = str_format_internal::FormatConversionCharToConvInt('f'), F = str_format_internal::FormatConversionCharToConvInt('F'), e = str_format_internal::FormatConversionCharToConvInt('e'), E = str_format_internal::FormatConversionCharToConvInt('E'), g = str_format_internal::FormatConversionCharToConvInt('g'), G = str_format_internal::FormatConversionCharToConvInt('G'), a = str_format_internal::FormatConversionCharToConvInt('a'), A = str_format_internal::FormatConversionCharToConvInt('A'), // misc n = str_format_internal::FormatConversionCharToConvInt('n'), p = str_format_internal::FormatConversionCharToConvInt('p'), v = str_format_internal::FormatConversionCharToConvInt('v'), // Used for width/precision '*' specification. kStar = static_cast( absl::str_format_internal::FormatConversionCharSetInternal::kStar), // Some predefined values: kIntegral = d | i | u | o | x | X, kFloating = a | e | f | g | A | E | F | G, kNumeric = kIntegral | kFloating, kString = s, kPointer = p, }; // FormatSink // // A format sink is a generic abstraction to which conversions may write their // formatted string data. `absl::FormatConvert()` uses this sink to write its // formatted string. // class FormatSink { public: // FormatSink::Append() // // Appends `count` copies of `ch` to the format sink. void Append(size_t count, char ch) { sink_->Append(count, ch); } // Overload of FormatSink::Append() for appending the characters of a string // view to a format sink. void Append(string_view v) { sink_->Append(v); } // FormatSink::PutPaddedString() // // Appends `precision` number of bytes of `v` to the format sink. If this is // less than `width`, spaces will be appended first (if `left` is false), or // after (if `left` is true) to ensure the total amount appended is // at least `width`. bool PutPaddedString(string_view v, int width, int precision, bool left) { return sink_->PutPaddedString(v, width, precision, left); } // Support `absl::Format(&sink, format, args...)`. friend void AbslFormatFlush(FormatSink* sink, absl::string_view v) { sink->Append(v); } private: friend str_format_internal::FormatSinkImpl; explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {} str_format_internal::FormatSinkImpl* sink_; }; // FormatConvertResult // // Indicates whether a call to AbslFormatConvert() was successful. // This return type informs the StrFormat extension framework (through // ADL but using the return type) of what conversion characters are supported. // It is strongly discouraged to return {false}, as this will result in an // empty string in StrFormat. template struct FormatConvertResult { bool value; }; ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_FORMAT_H_ s2/tools/vendor/abseil-cpp/absl/strings/ascii.h0000644000175000017510000002061714737212474021301 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: ascii.h // ----------------------------------------------------------------------------- // // This package contains functions operating on characters and strings // restricted to standard ASCII. These include character classification // functions analogous to those found in the ANSI C Standard Library // header file. // // C++ implementations provide functionality based on their // C environment locale. In general, reliance on such a locale is not ideal, as // the locale standard is problematic (and may not return invariant information // for the same character set, for example). These `ascii_*()` functions are // hard-wired for standard ASCII, much faster, and guaranteed to behave // consistently. They will never be overloaded, nor will their function // signature change. // // `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`, // `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`, // `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`, // `ascii_isxdigit()` // Analogous to the functions with similar names, these // functions take an unsigned char and return a bool, based on whether the // character matches the condition specified. // // If the input character has a numerical value greater than 127, these // functions return `false`. // // `ascii_tolower()`, `ascii_toupper()` // Analogous to the functions with similar names, these functions // take an unsigned char and return a char. // // If the input character is not an ASCII {lower,upper}-case letter (including // numerical values greater than 127) then the functions return the same value // as the input character. #ifndef ABSL_STRINGS_ASCII_H_ #define ABSL_STRINGS_ASCII_H_ #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace ascii_internal { // Declaration for an array of bitfields holding character information. ABSL_DLL extern const unsigned char kPropertyBits[256]; // Declaration for the array of characters to upper-case characters. ABSL_DLL extern const char kToUpper[256]; // Declaration for the array of characters to lower-case characters. ABSL_DLL extern const char kToLower[256]; } // namespace ascii_internal // ascii_isalpha() // // Determines whether the given character is an alphabetic character. inline bool ascii_isalpha(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x01) != 0; } // ascii_isalnum() // // Determines whether the given character is an alphanumeric character. inline bool ascii_isalnum(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x04) != 0; } // ascii_isspace() // // Determines whether the given character is a whitespace character (space, // tab, vertical tab, formfeed, linefeed, or carriage return). inline bool ascii_isspace(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x08) != 0; } // ascii_ispunct() // // Determines whether the given character is a punctuation character. inline bool ascii_ispunct(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x10) != 0; } // ascii_isblank() // // Determines whether the given character is a blank character (tab or space). inline bool ascii_isblank(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x20) != 0; } // ascii_iscntrl() // // Determines whether the given character is a control character. inline bool ascii_iscntrl(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x40) != 0; } // ascii_isxdigit() // // Determines whether the given character can be represented as a hexadecimal // digit character (i.e. {0-9} or {A-F}). inline bool ascii_isxdigit(unsigned char c) { return (ascii_internal::kPropertyBits[c] & 0x80) != 0; } // ascii_isdigit() // // Determines whether the given character can be represented as a decimal // digit character (i.e. {0-9}). inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; } // ascii_isprint() // // Determines whether the given character is printable, including spaces. inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; } // ascii_isgraph() // // Determines whether the given character has a graphical representation. inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; } // ascii_isupper() // // Determines whether the given character is uppercase. inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; } // ascii_islower() // // Determines whether the given character is lowercase. inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; } // ascii_isascii() // // Determines whether the given character is ASCII. inline bool ascii_isascii(unsigned char c) { return c < 128; } // ascii_tolower() // // Returns an ASCII character, converting to lowercase if uppercase is // passed. Note that character values > 127 are simply returned. inline char ascii_tolower(unsigned char c) { return ascii_internal::kToLower[c]; } // Converts the characters in `s` to lowercase, changing the contents of `s`. void AsciiStrToLower(std::string* s); // Creates a lowercase string from a given absl::string_view. ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) { std::string result(s); absl::AsciiStrToLower(&result); return result; } // ascii_toupper() // // Returns the ASCII character, converting to upper-case if lower-case is // passed. Note that characters values > 127 are simply returned. inline char ascii_toupper(unsigned char c) { return ascii_internal::kToUpper[c]; } // Converts the characters in `s` to uppercase, changing the contents of `s`. void AsciiStrToUpper(std::string* s); // Creates an uppercase string from a given absl::string_view. ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) { std::string result(s); absl::AsciiStrToUpper(&result); return result; } // Returns absl::string_view with whitespace stripped from the beginning of the // given string_view. ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace( absl::string_view str) { auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace); return str.substr(static_cast(it - str.begin())); } // Strips in place whitespace from the beginning of the given string. inline void StripLeadingAsciiWhitespace(std::string* str) { auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace); str->erase(str->begin(), it); } // Returns absl::string_view with whitespace stripped from the end of the given // string_view. ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace( absl::string_view str) { auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace); return str.substr(0, static_cast(str.rend() - it)); } // Strips in place whitespace from the end of the given string inline void StripTrailingAsciiWhitespace(std::string* str) { auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace); str->erase(static_cast(str->rend() - it)); } // Returns absl::string_view with whitespace stripped from both ends of the // given string_view. ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace( absl::string_view str) { return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str)); } // Strips in place whitespace from both ends of the given string inline void StripAsciiWhitespace(std::string* str) { StripTrailingAsciiWhitespace(str); StripLeadingAsciiWhitespace(str); } // Removes leading, trailing, and consecutive internal whitespace. void RemoveExtraAsciiWhitespace(std::string*); ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_ASCII_H_ s2/tools/vendor/abseil-cpp/absl/strings/cordz_test_helpers.h0000644000175000017510000001232414737212474024107 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_CORDZ_TEST_HELPERS_H_ #define ABSL_STRINGS_CORDZ_TEST_HELPERS_H_ #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/base/macros.h" #include "absl/strings/cord.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_info.h" #include "absl/strings/internal/cordz_sample_token.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/str_cat.h" namespace absl { ABSL_NAMESPACE_BEGIN // Returns the CordzInfo for the cord, or nullptr if the cord is not sampled. inline const cord_internal::CordzInfo* GetCordzInfoForTesting( const Cord& cord) { if (!cord.contents_.is_tree()) return nullptr; return cord.contents_.cordz_info(); } // Returns true if the provided cordz_info is in the list of sampled cords. inline bool CordzInfoIsListed(const cord_internal::CordzInfo* cordz_info, cord_internal::CordzSampleToken token = {}) { for (const cord_internal::CordzInfo& info : token) { if (cordz_info == &info) return true; } return false; } // Matcher on Cord that verifies all of: // - the cord is sampled // - the CordzInfo of the cord is listed / discoverable. // - the reported CordzStatistics match the cord's actual properties // - the cord has an (initial) UpdateTracker count of 1 for `method` MATCHER_P(HasValidCordzInfoOf, method, "CordzInfo matches cord") { const cord_internal::CordzInfo* cord_info = GetCordzInfoForTesting(arg); if (cord_info == nullptr) { *result_listener << "cord is not sampled"; return false; } if (!CordzInfoIsListed(cord_info)) { *result_listener << "cord is sampled, but not listed"; return false; } cord_internal::CordzStatistics stat = cord_info->GetCordzStatistics(); if (stat.size != arg.size()) { *result_listener << "cordz size " << stat.size << " does not match cord size " << arg.size(); return false; } if (stat.update_tracker.Value(method) != 1) { *result_listener << "Expected method count 1 for " << method << ", found " << stat.update_tracker.Value(method); return false; } return true; } // Matcher on Cord that verifies that the cord is sampled and that the CordzInfo // update tracker has 'method' with a call count of 'n' MATCHER_P2(CordzMethodCountEq, method, n, absl::StrCat("CordzInfo method count equals ", n)) { const cord_internal::CordzInfo* cord_info = GetCordzInfoForTesting(arg); if (cord_info == nullptr) { *result_listener << "cord is not sampled"; return false; } cord_internal::CordzStatistics stat = cord_info->GetCordzStatistics(); if (stat.update_tracker.Value(method) != n) { *result_listener << "Expected method count " << n << " for " << method << ", found " << stat.update_tracker.Value(method); return false; } return true; } // Cordz will only update with a new rate once the previously scheduled event // has fired. When we disable Cordz, a long delay takes place where we won't // consider profiling new Cords. CordzSampleIntervalHelper will burn through // that interval and allow for testing that assumes that the average sampling // interval is a particular value. class CordzSamplingIntervalHelper { public: explicit CordzSamplingIntervalHelper(int32_t interval) : orig_mean_interval_(absl::cord_internal::get_cordz_mean_interval()) { absl::cord_internal::set_cordz_mean_interval(interval); absl::cord_internal::cordz_set_next_sample_for_testing(interval); } ~CordzSamplingIntervalHelper() { absl::cord_internal::set_cordz_mean_interval(orig_mean_interval_); absl::cord_internal::cordz_set_next_sample_for_testing(orig_mean_interval_); } private: int32_t orig_mean_interval_; }; // Wrapper struct managing a small CordRep `rep` struct TestCordRep { cord_internal::CordRepFlat* rep; TestCordRep() { rep = cord_internal::CordRepFlat::New(100); rep->length = 100; memset(rep->Data(), 1, 100); } ~TestCordRep() { cord_internal::CordRep::Unref(rep); } }; // Wrapper struct managing a small CordRep `rep`, and // an InlineData `data` initialized with that CordRep. struct TestCordData { TestCordRep rep; cord_internal::InlineData data{rep.rep}; }; // Creates a Cord that is not sampled template Cord UnsampledCord(Args... args) { CordzSamplingIntervalHelper never(9999); Cord cord(std::forward(args)...); ABSL_ASSERT(GetCordzInfoForTesting(cord) == nullptr); return cord; } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CORDZ_TEST_HELPERS_H_ s2/tools/vendor/abseil-cpp/absl/strings/charconv.cc0000644000175000017510000021150414737212474022147 0ustar nileshnilesh// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/charconv.h" #include #include #include #include #include #include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/numeric/bits.h" #include "absl/numeric/int128.h" #include "absl/strings/internal/charconv_bigint.h" #include "absl/strings/internal/charconv_parse.h" // The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating // point numbers have the same endianness in memory as a bitfield struct // containing the corresponding parts. // // When set, we replace calls to ldexp() with manual bit packing, which is // faster and is unaffected by floating point environment. #ifdef ABSL_BIT_PACK_FLOATS #error ABSL_BIT_PACK_FLOATS cannot be directly set #elif defined(__x86_64__) || defined(_M_X64) #define ABSL_BIT_PACK_FLOATS 1 #endif // A note about subnormals: // // The code below talks about "normals" and "subnormals". A normal IEEE float // has a fixed-width mantissa and power of two exponent. For example, a normal // `double` has a 53-bit mantissa. Because the high bit is always 1, it is not // stored in the representation. The implicit bit buys an extra bit of // resolution in the datatype. // // The downside of this scheme is that there is a large gap between DBL_MIN and // zero. (Large, at least, relative to the different between DBL_MIN and the // next representable number). This gap is softened by the "subnormal" numbers, // which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd // bit. An all-bits-zero exponent in the encoding represents subnormals. (Zero // is represented as a subnormal with an all-bits-zero mantissa.) // // The code below, in calculations, represents the mantissa as a uint64_t. The // end result normally has the 53rd bit set. It represents subnormals by using // narrower mantissas. namespace absl { ABSL_NAMESPACE_BEGIN namespace { template struct FloatTraits; template <> struct FloatTraits { using mantissa_t = uint64_t; // The number of bits in the given float type. static constexpr int kTargetBits = 64; // The number of exponent bits in the given float type. static constexpr int kTargetExponentBits = 11; // The number of mantissa bits in the given float type. This includes the // implied high bit. static constexpr int kTargetMantissaBits = 53; // The largest supported IEEE exponent, in our integral mantissa // representation. // // If `m` is the largest possible int kTargetMantissaBits bits wide, then // m * 2**kMaxExponent is exactly equal to DBL_MAX. static constexpr int kMaxExponent = 971; // The smallest supported IEEE normal exponent, in our integral mantissa // representation. // // If `m` is the smallest possible int kTargetMantissaBits bits wide, then // m * 2**kMinNormalExponent is exactly equal to DBL_MIN. static constexpr int kMinNormalExponent = -1074; // The IEEE exponent bias. It equals ((1 << (kTargetExponentBits - 1)) - 1). static constexpr int kExponentBias = 1023; // The Eisel-Lemire "Shifting to 54/25 Bits" adjustment. It equals (63 - 1 - // kTargetMantissaBits). static constexpr int kEiselLemireShift = 9; // The Eisel-Lemire high64_mask. It equals ((1 << kEiselLemireShift) - 1). static constexpr uint64_t kEiselLemireMask = uint64_t{0x1FF}; // The smallest negative integer N (smallest negative means furthest from // zero) such that parsing 9999999999999999999eN, with 19 nines, is still // positive. Parsing a smaller (more negative) N will produce zero. // // Adjusting the decimal point and exponent, without adjusting the value, // 9999999999999999999eN equals 9.999999999999999999eM where M = N + 18. // // 9999999999999999999, with 19 nines but no decimal point, is the largest // "repeated nines" integer that fits in a uint64_t. static constexpr int kEiselLemireMinInclusiveExp10 = -324 - 18; // The smallest positive integer N such that parsing 1eN produces infinity. // Parsing a smaller N will produce something finite. static constexpr int kEiselLemireMaxExclusiveExp10 = 309; static double MakeNan(const char* tagp) { #if ABSL_HAVE_BUILTIN(__builtin_nan) // Use __builtin_nan() if available since it has a fix for // https://bugs.llvm.org/show_bug.cgi?id=37778 // std::nan may use the glibc implementation. return __builtin_nan(tagp); #else // Support nan no matter which namespace it's in. Some platforms // incorrectly don't put it in namespace std. using namespace std; // NOLINT return nan(tagp); #endif } // Builds a nonzero floating point number out of the provided parts. // // This is intended to do the same operation as ldexp(mantissa, exponent), // but using purely integer math, to avoid -ffastmath and floating // point environment issues. Using type punning is also faster. We fall back // to ldexp on a per-platform basis for portability. // // `exponent` must be between kMinNormalExponent and kMaxExponent. // // `mantissa` must either be exactly kTargetMantissaBits wide, in which case // a normal value is made, or it must be less narrow than that, in which case // `exponent` must be exactly kMinNormalExponent, and a subnormal value is // made. static double Make(mantissa_t mantissa, int exponent, bool sign) { #ifndef ABSL_BIT_PACK_FLOATS // Support ldexp no matter which namespace it's in. Some platforms // incorrectly don't put it in namespace std. using namespace std; // NOLINT return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent); #else constexpr uint64_t kMantissaMask = (uint64_t{1} << (kTargetMantissaBits - 1)) - 1; uint64_t dbl = static_cast(sign) << 63; if (mantissa > kMantissaMask) { // Normal value. // Adjust by 1023 for the exponent representation bias, and an additional // 52 due to the implied decimal point in the IEEE mantissa // representation. dbl += static_cast(exponent + 1023 + kTargetMantissaBits - 1) << 52; mantissa &= kMantissaMask; } else { // subnormal value assert(exponent == kMinNormalExponent); } dbl += mantissa; return absl::bit_cast(dbl); #endif // ABSL_BIT_PACK_FLOATS } }; // Specialization of floating point traits for the `float` type. See the // FloatTraits specialization above for meaning of each of the following // members and methods. template <> struct FloatTraits { using mantissa_t = uint32_t; static constexpr int kTargetBits = 32; static constexpr int kTargetExponentBits = 8; static constexpr int kTargetMantissaBits = 24; static constexpr int kMaxExponent = 104; static constexpr int kMinNormalExponent = -149; static constexpr int kExponentBias = 127; static constexpr int kEiselLemireShift = 38; static constexpr uint64_t kEiselLemireMask = uint64_t{0x3FFFFFFFFF}; static constexpr int kEiselLemireMinInclusiveExp10 = -46 - 18; static constexpr int kEiselLemireMaxExclusiveExp10 = 39; static float MakeNan(const char* tagp) { #if ABSL_HAVE_BUILTIN(__builtin_nanf) // Use __builtin_nanf() if available since it has a fix for // https://bugs.llvm.org/show_bug.cgi?id=37778 // std::nanf may use the glibc implementation. return __builtin_nanf(tagp); #else // Support nanf no matter which namespace it's in. Some platforms // incorrectly don't put it in namespace std. using namespace std; // NOLINT return std::nanf(tagp); #endif } static float Make(mantissa_t mantissa, int exponent, bool sign) { #ifndef ABSL_BIT_PACK_FLOATS // Support ldexpf no matter which namespace it's in. Some platforms // incorrectly don't put it in namespace std. using namespace std; // NOLINT return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent); #else constexpr uint32_t kMantissaMask = (uint32_t{1} << (kTargetMantissaBits - 1)) - 1; uint32_t flt = static_cast(sign) << 31; if (mantissa > kMantissaMask) { // Normal value. // Adjust by 127 for the exponent representation bias, and an additional // 23 due to the implied decimal point in the IEEE mantissa // representation. flt += static_cast(exponent + 127 + kTargetMantissaBits - 1) << 23; mantissa &= kMantissaMask; } else { // subnormal value assert(exponent == kMinNormalExponent); } flt += mantissa; return absl::bit_cast(flt); #endif // ABSL_BIT_PACK_FLOATS } }; // Decimal-to-binary conversions require coercing powers of 10 into a mantissa // and a power of 2. The two helper functions Power10Mantissa(n) and // Power10Exponent(n) perform this task. Together, these represent a hand- // rolled floating point value which is equal to or just less than 10**n. // // The return values satisfy two range guarantees: // // Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n // < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n) // // 2**63 <= Power10Mantissa(n) < 2**64. // // See the "Table of powers of 10" comment below for a "1e60" example. // // Lookups into the power-of-10 table must first check the Power10Overflow() and // Power10Underflow() functions, to avoid out-of-bounds table access. // // Indexes into these tables are biased by -kPower10TableMinInclusive. Valid // indexes range from kPower10TableMinInclusive to kPower10TableMaxExclusive. extern const uint64_t kPower10MantissaHighTable[]; // High 64 of 128 bits. extern const uint64_t kPower10MantissaLowTable[]; // Low 64 of 128 bits. // The smallest (inclusive) allowed value for use with the Power10Mantissa() // and Power10Exponent() functions below. (If a smaller exponent is needed in // calculations, the end result is guaranteed to underflow.) constexpr int kPower10TableMinInclusive = -342; // The largest (exclusive) allowed value for use with the Power10Mantissa() and // Power10Exponent() functions below. (If a larger-or-equal exponent is needed // in calculations, the end result is guaranteed to overflow.) constexpr int kPower10TableMaxExclusive = 309; uint64_t Power10Mantissa(int n) { return kPower10MantissaHighTable[n - kPower10TableMinInclusive]; } int Power10Exponent(int n) { // The 217706 etc magic numbers encode the results as a formula instead of a // table. Their equivalence (over the kPower10TableMinInclusive .. // kPower10TableMaxExclusive range) is confirmed by // https://github.com/google/wuffs/blob/315b2e52625ebd7b02d8fac13e3cd85ea374fb80/script/print-mpb-powers-of-10.go return (217706 * n >> 16) - 63; } // Returns true if n is large enough that 10**n always results in an IEEE // overflow. bool Power10Overflow(int n) { return n >= kPower10TableMaxExclusive; } // Returns true if n is small enough that 10**n times a ParsedFloat mantissa // always results in an IEEE underflow. bool Power10Underflow(int n) { return n < kPower10TableMinInclusive; } // Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal // to 10**n numerically. Put another way, this returns true if there is no // truncation error in Power10Mantissa(n). bool Power10Exact(int n) { return n >= 0 && n <= 27; } // Sentinel exponent values for representing numbers too large or too close to // zero to represent in a double. constexpr int kOverflow = 99999; constexpr int kUnderflow = -99999; // Struct representing the calculated conversion result of a positive (nonzero) // floating point number. // // The calculated number is mantissa * 2**exponent (mantissa is treated as an // integer.) `mantissa` is chosen to be the correct width for the IEEE float // representation being calculated. (`mantissa` will always have the same bit // width for normal values, and narrower bit widths for subnormals.) // // If the result of conversion was an underflow or overflow, exponent is set // to kUnderflow or kOverflow. struct CalculatedFloat { uint64_t mantissa = 0; int exponent = 0; }; // Returns the bit width of the given uint128. (Equivalently, returns 128 // minus the number of leading zero bits.) int BitWidth(uint128 value) { if (Uint128High64(value) == 0) { // This static_cast is only needed when using a std::bit_width() // implementation that does not have the fix for LWG 3656 applied. return static_cast(bit_width(Uint128Low64(value))); } return 128 - countl_zero(Uint128High64(value)); } // Calculates how far to the right a mantissa needs to be shifted to create a // properly adjusted mantissa for an IEEE floating point number. // // `mantissa_width` is the bit width of the mantissa to be shifted, and // `binary_exponent` is the exponent of the number before the shift. // // This accounts for subnormal values, and will return a larger-than-normal // shift if binary_exponent would otherwise be too low. template int NormalizedShiftSize(int mantissa_width, int binary_exponent) { const int normal_shift = mantissa_width - FloatTraits::kTargetMantissaBits; const int minimum_shift = FloatTraits::kMinNormalExponent - binary_exponent; return std::max(normal_shift, minimum_shift); } // Right shifts a uint128 so that it has the requested bit width. (The // resulting value will have 128 - bit_width leading zeroes.) The initial // `value` must be wider than the requested bit width. // // Returns the number of bits shifted. int TruncateToBitWidth(int bit_width, uint128* value) { const int current_bit_width = BitWidth(*value); const int shift = current_bit_width - bit_width; *value >>= shift; return shift; } // Checks if the given ParsedFloat represents one of the edge cases that are // not dependent on number base: zero, infinity, or NaN. If so, sets *value // the appropriate double, and returns true. template bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, FloatType* value) { if (input.type == strings_internal::FloatType::kNan) { // A bug in both clang < 7 and gcc would cause the compiler to optimize // away the buffer we are building below. Declaring the buffer volatile // avoids the issue, and has no measurable performance impact in // microbenchmarks. // // https://bugs.llvm.org/show_bug.cgi?id=37778 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113 constexpr ptrdiff_t kNanBufferSize = 128; #if (defined(__GNUC__) && !defined(__clang__)) || \ (defined(__clang__) && __clang_major__ < 7) volatile char n_char_sequence[kNanBufferSize]; #else char n_char_sequence[kNanBufferSize]; #endif if (input.subrange_begin == nullptr) { n_char_sequence[0] = '\0'; } else { ptrdiff_t nan_size = input.subrange_end - input.subrange_begin; nan_size = std::min(nan_size, kNanBufferSize - 1); std::copy_n(input.subrange_begin, nan_size, n_char_sequence); n_char_sequence[nan_size] = '\0'; } char* nan_argument = const_cast(n_char_sequence); *value = negative ? -FloatTraits::MakeNan(nan_argument) : FloatTraits::MakeNan(nan_argument); return true; } if (input.type == strings_internal::FloatType::kInfinity) { *value = negative ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); return true; } if (input.mantissa == 0) { *value = negative ? -0.0 : 0.0; return true; } return false; } // Given a CalculatedFloat result of a from_chars conversion, generate the // correct output values. // // CalculatedFloat can represent an underflow or overflow, in which case the // error code in *result is set. Otherwise, the calculated floating point // number is stored in *value. template void EncodeResult(const CalculatedFloat& calculated, bool negative, absl::from_chars_result* result, FloatType* value) { if (calculated.exponent == kOverflow) { result->ec = std::errc::result_out_of_range; *value = negative ? -std::numeric_limits::max() : std::numeric_limits::max(); return; } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) { result->ec = std::errc::result_out_of_range; *value = negative ? -0.0 : 0.0; return; } *value = FloatTraits::Make( static_cast::mantissa_t>( calculated.mantissa), calculated.exponent, negative); } // Returns the given uint128 shifted to the right by `shift` bits, and rounds // the remaining bits using round_to_nearest logic. The value is returned as a // uint64_t, since this is the type used by this library for storing calculated // floating point mantissas. // // It is expected that the width of the input value shifted by `shift` will // be the correct bit-width for the target mantissa, which is strictly narrower // than a uint64_t. // // If `input_exact` is false, then a nonzero error epsilon is assumed. For // rounding purposes, the true value being rounded is strictly greater than the // input value. The error may represent a single lost carry bit. // // When input_exact, shifted bits of the form 1000000... represent a tie, which // is broken by rounding to even -- the rounding direction is chosen so the low // bit of the returned value is 0. // // When !input_exact, shifted bits of the form 10000000... represent a value // strictly greater than one half (due to the error epsilon), and so ties are // always broken by rounding up. // // When !input_exact, shifted bits of the form 01111111... are uncertain; // the true value may or may not be greater than 10000000..., due to the // possible lost carry bit. The correct rounding direction is unknown. In this // case, the result is rounded down, and `output_exact` is set to false. // // Zero and negative values of `shift` are accepted, in which case the word is // shifted left, as necessary. uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact, bool* output_exact) { if (shift <= 0) { *output_exact = input_exact; return static_cast(value << -shift); } if (shift >= 128) { // Exponent is so small that we are shifting away all significant bits. // Answer will not be representable, even as a subnormal, so return a zero // mantissa (which represents underflow). *output_exact = true; return 0; } *output_exact = true; const uint128 shift_mask = (uint128(1) << shift) - 1; const uint128 halfway_point = uint128(1) << (shift - 1); const uint128 shifted_bits = value & shift_mask; value >>= shift; if (shifted_bits > halfway_point) { // Shifted bits greater than 10000... require rounding up. return static_cast(value + 1); } if (shifted_bits == halfway_point) { // In exact mode, shifted bits of 10000... mean we're exactly halfway // between two numbers, and we must round to even. So only round up if // the low bit of `value` is set. // // In inexact mode, the nonzero error means the actual value is greater // than the halfway point and we must always round up. if ((value & 1) == 1 || !input_exact) { ++value; } return static_cast(value); } if (!input_exact && shifted_bits == halfway_point - 1) { // Rounding direction is unclear, due to error. *output_exact = false; } // Otherwise, round down. return static_cast(value); } // Checks if a floating point guess needs to be rounded up, using high precision // math. // // `guess_mantissa` and `guess_exponent` represent a candidate guess for the // number represented by `parsed_decimal`. // // The exact number represented by `parsed_decimal` must lie between the two // numbers: // A = `guess_mantissa * 2**guess_exponent` // B = `(guess_mantissa + 1) * 2**guess_exponent` // // This function returns false if `A` is the better guess, and true if `B` is // the better guess, with rounding ties broken by rounding to even. bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent, const strings_internal::ParsedFloat& parsed_decimal) { // 768 is the number of digits needed in the worst case. We could determine a // better limit dynamically based on the value of parsed_decimal.exponent. // This would optimize pathological input cases only. (Sane inputs won't have // hundreds of digits of mantissa.) absl::strings_internal::BigUnsigned<84> exact_mantissa; int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768); // Adjust the `guess` arguments to be halfway between A and B. guess_mantissa = guess_mantissa * 2 + 1; guess_exponent -= 1; // In our comparison: // lhs = exact = exact_mantissa * 10**exact_exponent // = exact_mantissa * 5**exact_exponent * 2**exact_exponent // rhs = guess = guess_mantissa * 2**guess_exponent // // Because we are doing integer math, we can't directly deal with negative // exponents. We instead move these to the other side of the inequality. absl::strings_internal::BigUnsigned<84>& lhs = exact_mantissa; int comparison; if (exact_exponent >= 0) { lhs.MultiplyByFiveToTheNth(exact_exponent); absl::strings_internal::BigUnsigned<84> rhs(guess_mantissa); // There are powers of 2 on both sides of the inequality; reduce this to // a single bit-shift. if (exact_exponent > guess_exponent) { lhs.ShiftLeft(exact_exponent - guess_exponent); } else { rhs.ShiftLeft(guess_exponent - exact_exponent); } comparison = Compare(lhs, rhs); } else { // Move the power of 5 to the other side of the equation, giving us: // lhs = exact_mantissa * 2**exact_exponent // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent absl::strings_internal::BigUnsigned<84> rhs = absl::strings_internal::BigUnsigned<84>::FiveToTheNth(-exact_exponent); rhs.MultiplyBy(guess_mantissa); if (exact_exponent > guess_exponent) { lhs.ShiftLeft(exact_exponent - guess_exponent); } else { rhs.ShiftLeft(guess_exponent - exact_exponent); } comparison = Compare(lhs, rhs); } if (comparison < 0) { return false; } else if (comparison > 0) { return true; } else { // When lhs == rhs, the decimal input is exactly between A and B. // Round towards even -- round up only if the low bit of the initial // `guess_mantissa` was a 1. We shifted guess_mantissa left 1 bit at // the beginning of this function, so test the 2nd bit here. return (guess_mantissa & 2) == 2; } } // Constructs a CalculatedFloat from a given mantissa and exponent, but // with the following normalizations applied: // // If rounding has caused mantissa to increase just past the allowed bit // width, shift and adjust exponent. // // If exponent is too high, sets kOverflow. // // If mantissa is zero (representing a non-zero value not representable, even // as a subnormal), sets kUnderflow. template CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) { CalculatedFloat result; if (mantissa == uint64_t{1} << FloatTraits::kTargetMantissaBits) { mantissa >>= 1; exponent += 1; } if (exponent > FloatTraits::kMaxExponent) { result.exponent = kOverflow; } else if (mantissa == 0) { result.exponent = kUnderflow; } else { result.exponent = exponent; result.mantissa = mantissa; } return result; } template CalculatedFloat CalculateFromParsedHexadecimal( const strings_internal::ParsedFloat& parsed_hex) { uint64_t mantissa = parsed_hex.mantissa; int exponent = parsed_hex.exponent; // This static_cast is only needed when using a std::bit_width() // implementation that does not have the fix for LWG 3656 applied. int mantissa_width = static_cast(bit_width(mantissa)); const int shift = NormalizedShiftSize(mantissa_width, exponent); bool result_exact; exponent += shift; mantissa = ShiftRightAndRound(mantissa, shift, /* input exact= */ true, &result_exact); // ParseFloat handles rounding in the hexadecimal case, so we don't have to // check `result_exact` here. return CalculatedFloatFromRawValues(mantissa, exponent); } template CalculatedFloat CalculateFromParsedDecimal( const strings_internal::ParsedFloat& parsed_decimal) { CalculatedFloat result; // Large or small enough decimal exponents will always result in overflow // or underflow. if (Power10Underflow(parsed_decimal.exponent)) { result.exponent = kUnderflow; return result; } else if (Power10Overflow(parsed_decimal.exponent)) { result.exponent = kOverflow; return result; } // Otherwise convert our power of 10 into a power of 2 times an integer // mantissa, and multiply this by our parsed decimal mantissa. uint128 wide_binary_mantissa = parsed_decimal.mantissa; wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent); int binary_exponent = Power10Exponent(parsed_decimal.exponent); // Discard bits that are inaccurate due to truncation error. The magic // `mantissa_width` constants below are justified in // https://abseil.io/about/design/charconv. They represent the number of bits // in `wide_binary_mantissa` that are guaranteed to be unaffected by error // propagation. bool mantissa_exact; int mantissa_width; if (parsed_decimal.subrange_begin) { // Truncated mantissa mantissa_width = 58; mantissa_exact = false; binary_exponent += TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); } else if (!Power10Exact(parsed_decimal.exponent)) { // Exact mantissa, truncated power of ten mantissa_width = 63; mantissa_exact = false; binary_exponent += TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); } else { // Product is exact mantissa_width = BitWidth(wide_binary_mantissa); mantissa_exact = true; } // Shift into an FloatType-sized mantissa, and round to nearest. const int shift = NormalizedShiftSize(mantissa_width, binary_exponent); bool result_exact; binary_exponent += shift; uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift, mantissa_exact, &result_exact); if (!result_exact) { // We could not determine the rounding direction using int128 math. Use // full resolution math instead. if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) { binary_mantissa += 1; } } return CalculatedFloatFromRawValues(binary_mantissa, binary_exponent); } // As discussed in https://nigeltao.github.io/blog/2020/eisel-lemire.html the // primary goal of the Eisel-Lemire algorithm is speed, for 99+% of the cases, // not 100% coverage. As long as Eisel-Lemire doesn’t claim false positives, // the combined approach (falling back to an alternative implementation when // this function returns false) is both fast and correct. template bool EiselLemire(const strings_internal::ParsedFloat& input, bool negative, FloatType* value, std::errc* ec) { uint64_t man = input.mantissa; int exp10 = input.exponent; if (exp10 < FloatTraits::kEiselLemireMinInclusiveExp10) { *value = negative ? -0.0 : 0.0; *ec = std::errc::result_out_of_range; return true; } else if (exp10 >= FloatTraits::kEiselLemireMaxExclusiveExp10) { // Return max (a finite value) consistent with from_chars and DR 3081. For // SimpleAtod and SimpleAtof, post-processing will return infinity. *value = negative ? -std::numeric_limits::max() : std::numeric_limits::max(); *ec = std::errc::result_out_of_range; return true; } // Assert kPower10TableMinInclusive <= exp10 < kPower10TableMaxExclusive. // Equivalently, !Power10Underflow(exp10) and !Power10Overflow(exp10). static_assert( FloatTraits::kEiselLemireMinInclusiveExp10 >= kPower10TableMinInclusive, "(exp10-kPower10TableMinInclusive) in kPower10MantissaHighTable bounds"); static_assert( FloatTraits::kEiselLemireMaxExclusiveExp10 <= kPower10TableMaxExclusive, "(exp10-kPower10TableMinInclusive) in kPower10MantissaHighTable bounds"); // The terse (+) comments in this function body refer to sections of the // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. // // That blog post discusses double precision (11 exponent bits with a -1023 // bias, 52 mantissa bits), but the same approach applies to single precision // (8 exponent bits with a -127 bias, 23 mantissa bits). Either way, the // computation here happens with 64-bit values (e.g. man) or 128-bit values // (e.g. x) before finally converting to 64- or 32-bit floating point. // // See also "Number Parsing at a Gigabyte per Second, Software: Practice and // Experience 51 (8), 2021" (https://arxiv.org/abs/2101.11408) for detail. // (+) Normalization. int clz = countl_zero(man); man <<= static_cast(clz); // The 217706 etc magic numbers are from the Power10Exponent function. uint64_t ret_exp2 = static_cast((217706 * exp10 >> 16) + 64 + FloatTraits::kExponentBias - clz); // (+) Multiplication. uint128 x = static_cast(man) * static_cast( kPower10MantissaHighTable[exp10 - kPower10TableMinInclusive]); // (+) Wider Approximation. static constexpr uint64_t high64_mask = FloatTraits::kEiselLemireMask; if (((Uint128High64(x) & high64_mask) == high64_mask) && (man > (std::numeric_limits::max() - Uint128Low64(x)))) { uint128 y = static_cast(man) * static_cast( kPower10MantissaLowTable[exp10 - kPower10TableMinInclusive]); x += Uint128High64(y); // For example, parsing "4503599627370497.5" will take the if-true // branch here (for double precision), since: // - x = 0x8000000000000BFF_FFFFFFFFFFFFFFFF // - y = 0x8000000000000BFF_7FFFFFFFFFFFF400 // - man = 0xA000000000000F00 // Likewise, when parsing "0.0625" for single precision: // - x = 0x7FFFFFFFFFFFFFFF_FFFFFFFFFFFFFFFF // - y = 0x813FFFFFFFFFFFFF_8A00000000000000 // - man = 0x9C40000000000000 if (((Uint128High64(x) & high64_mask) == high64_mask) && ((Uint128Low64(x) + 1) == 0) && (man > (std::numeric_limits::max() - Uint128Low64(y)))) { return false; } } // (+) Shifting to 54 Bits (or for single precision, to 25 bits). uint64_t msb = Uint128High64(x) >> 63; uint64_t ret_man = Uint128High64(x) >> (msb + FloatTraits::kEiselLemireShift); ret_exp2 -= 1 ^ msb; // (+) Half-way Ambiguity. // // For example, parsing "1e+23" will take the if-true branch here (for double // precision), since: // - x = 0x54B40B1F852BDA00_0000000000000000 // - ret_man = 0x002A5A058FC295ED // Likewise, when parsing "20040229.0" for single precision: // - x = 0x4C72894000000000_0000000000000000 // - ret_man = 0x000000000131CA25 if ((Uint128Low64(x) == 0) && ((Uint128High64(x) & high64_mask) == 0) && ((ret_man & 3) == 1)) { return false; } // (+) From 54 to 53 Bits (or for single precision, from 25 to 24 bits). ret_man += ret_man & 1; // Line From54a. ret_man >>= 1; // Line From54b. // Incrementing ret_man (at line From54a) may have overflowed 54 bits (53 // bits after the right shift by 1 at line From54b), so adjust for that. // // For example, parsing "9223372036854775807" will take the if-true branch // here (for double precision), since: // - ret_man = 0x0020000000000000 = (1 << 53) // Likewise, when parsing "2147483647.0" for single precision: // - ret_man = 0x0000000001000000 = (1 << 24) if ((ret_man >> FloatTraits::kTargetMantissaBits) > 0) { ret_exp2 += 1; // Conceptually, we need a "ret_man >>= 1" in this if-block to balance // incrementing ret_exp2 in the line immediately above. However, we only // get here when line From54a overflowed (after adding a 1), so ret_man // here is (1 << 53). Its low 53 bits are therefore all zeroes. The only // remaining use of ret_man is to mask it with ((1 << 52) - 1), so only its // low 52 bits matter. A "ret_man >>= 1" would have no effect in practice. // // We omit the "ret_man >>= 1", even if it is cheap (and this if-branch is // rarely taken) and technically 'more correct', so that mutation tests // that would otherwise modify or omit that "ret_man >>= 1" don't complain // that such code mutations have no observable effect. } // ret_exp2 is a uint64_t. Zero or underflow means that we're in subnormal // space. max_exp2 (0x7FF for double precision, 0xFF for single precision) or // above means that we're in Inf/NaN space. // // The if block is equivalent to (but has fewer branches than): // if ((ret_exp2 <= 0) || (ret_exp2 >= max_exp2)) { etc } // // For example, parsing "4.9406564584124654e-324" will take the if-true // branch here, since ret_exp2 = -51. static constexpr uint64_t max_exp2 = (1 << FloatTraits::kTargetExponentBits) - 1; if ((ret_exp2 - 1) >= (max_exp2 - 1)) { return false; } #ifndef ABSL_BIT_PACK_FLOATS if (FloatTraits::kTargetBits == 64) { *value = FloatTraits::Make( (ret_man & 0x000FFFFFFFFFFFFFu) | 0x0010000000000000u, static_cast(ret_exp2) - 1023 - 52, negative); return true; } else if (FloatTraits::kTargetBits == 32) { *value = FloatTraits::Make( (static_cast(ret_man) & 0x007FFFFFu) | 0x00800000u, static_cast(ret_exp2) - 127 - 23, negative); return true; } #else if (FloatTraits::kTargetBits == 64) { uint64_t ret_bits = (ret_exp2 << 52) | (ret_man & 0x000FFFFFFFFFFFFFu); if (negative) { ret_bits |= 0x8000000000000000u; } *value = absl::bit_cast(ret_bits); return true; } else if (FloatTraits::kTargetBits == 32) { uint32_t ret_bits = (static_cast(ret_exp2) << 23) | (static_cast(ret_man) & 0x007FFFFFu); if (negative) { ret_bits |= 0x80000000u; } *value = absl::bit_cast(ret_bits); return true; } #endif // ABSL_BIT_PACK_FLOATS return false; } template from_chars_result FromCharsImpl(const char* first, const char* last, FloatType& value, chars_format fmt_flags) { from_chars_result result; result.ptr = first; // overwritten on successful parse result.ec = std::errc(); bool negative = false; if (first != last && *first == '-') { ++first; negative = true; } // If the `hex` flag is *not* set, then we will accept a 0x prefix and try // to parse a hexadecimal float. if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 && *first == '0' && (first[1] == 'x' || first[1] == 'X')) { const char* hex_first = first + 2; strings_internal::ParsedFloat hex_parse = strings_internal::ParseFloat<16>(hex_first, last, fmt_flags); if (hex_parse.end == nullptr || hex_parse.type != strings_internal::FloatType::kNumber) { // Either we failed to parse a hex float after the "0x", or we read // "0xinf" or "0xnan" which we don't want to match. // // However, a string that begins with "0x" also begins with "0", which // is normally a valid match for the number zero. So we want these // strings to match zero unless fmt_flags is `scientific`. (This flag // means an exponent is required, which the string "0" does not have.) if (fmt_flags == chars_format::scientific) { result.ec = std::errc::invalid_argument; } else { result.ptr = first + 1; value = negative ? -0.0 : 0.0; } return result; } // We matched a value. result.ptr = hex_parse.end; if (HandleEdgeCase(hex_parse, negative, &value)) { return result; } CalculatedFloat calculated = CalculateFromParsedHexadecimal(hex_parse); EncodeResult(calculated, negative, &result, &value); return result; } // Otherwise, we choose the number base based on the flags. if ((fmt_flags & chars_format::hex) == chars_format::hex) { strings_internal::ParsedFloat hex_parse = strings_internal::ParseFloat<16>(first, last, fmt_flags); if (hex_parse.end == nullptr) { result.ec = std::errc::invalid_argument; return result; } result.ptr = hex_parse.end; if (HandleEdgeCase(hex_parse, negative, &value)) { return result; } CalculatedFloat calculated = CalculateFromParsedHexadecimal(hex_parse); EncodeResult(calculated, negative, &result, &value); return result; } else { strings_internal::ParsedFloat decimal_parse = strings_internal::ParseFloat<10>(first, last, fmt_flags); if (decimal_parse.end == nullptr) { result.ec = std::errc::invalid_argument; return result; } result.ptr = decimal_parse.end; if (HandleEdgeCase(decimal_parse, negative, &value)) { return result; } // A nullptr subrange_begin means that the decimal_parse.mantissa is exact // (not truncated), a precondition of the Eisel-Lemire algorithm. if ((decimal_parse.subrange_begin == nullptr) && EiselLemire(decimal_parse, negative, &value, &result.ec)) { return result; } CalculatedFloat calculated = CalculateFromParsedDecimal(decimal_parse); EncodeResult(calculated, negative, &result, &value); return result; } } } // namespace from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt) { return FromCharsImpl(first, last, value, fmt); } from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt) { return FromCharsImpl(first, last, value, fmt); } namespace { // Table of powers of 10, from kPower10TableMinInclusive to // kPower10TableMaxExclusive. // // kPower10MantissaHighTable[i - kPower10TableMinInclusive] stores the 64-bit // mantissa. The high bit is always on. // // kPower10MantissaLowTable extends that 64-bit mantissa to 128 bits. // // Power10Exponent(i) calculates the power-of-two exponent. // // For a number i, this gives the unique mantissaHigh and exponent such that // (mantissaHigh * 2**exponent) <= 10**i < ((mantissaHigh + 1) * 2**exponent). // // For example, Python can confirm that the exact hexadecimal value of 1e60 is: // >>> a = 1000000000000000000000000000000000000000000000000000000000000 // >>> hex(a) // '0x9f4f2726179a224501d762422c946590d91000000000000000' // Adding underscores at every 8th hex digit shows 50 hex digits: // '0x9f4f2726_179a2245_01d76242_2c946590_d9100000_00000000_00'. // In this case, the high bit of the first hex digit, 9, is coincidentally set, // so we do not have to do further shifting to deduce the 128-bit mantissa: // - kPower10MantissaHighTable[60 - kP10TMI] = 0x9f4f2726179a2245U // - kPower10MantissaLowTable[ 60 - kP10TMI] = 0x01d762422c946590U // where kP10TMI is kPower10TableMinInclusive. The low 18 of those 50 hex // digits are truncated. // // 50 hex digits (with the high bit set) is 200 bits and mantissaHigh holds 64 // bits, so Power10Exponent(60) = 200 - 64 = 136. Again, Python can confirm: // >>> b = 0x9f4f2726179a2245 // >>> ((b+0)<<136) <= a // True // >>> ((b+1)<<136) <= a // False // // The tables were generated by // https://github.com/google/wuffs/blob/315b2e52625ebd7b02d8fac13e3cd85ea374fb80/script/print-mpb-powers-of-10.go // after re-formatting its output into two arrays of N uint64_t values (instead // of an N element array of uint64_t pairs). const uint64_t kPower10MantissaHighTable[] = { 0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U, 0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U, 0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU, 0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U, 0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U, 0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U, 0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU, 0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U, 0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU, 0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU, 0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U, 0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU, 0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U, 0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU, 0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU, 0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU, 0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU, 0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U, 0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU, 0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU, 0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U, 0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U, 0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU, 0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U, 0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U, 0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U, 0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU, 0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U, 0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U, 0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U, 0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U, 0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U, 0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU, 0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U, 0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU, 0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU, 0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U, 0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U, 0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU, 0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U, 0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU, 0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU, 0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U, 0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU, 0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U, 0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U, 0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU, 0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU, 0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U, 0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U, 0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU, 0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U, 0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U, 0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU, 0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU, 0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU, 0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU, 0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U, 0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU, 0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU, 0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U, 0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU, 0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU, 0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U, 0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U, 0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U, 0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU, 0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U, 0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU, 0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U, 0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU, 0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U, 0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU, 0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU, 0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U, 0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U, 0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU, 0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U, 0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U, 0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU, 0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU, 0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U, 0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U, 0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U, 0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU, 0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U, 0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU, 0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU, 0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU, 0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U, 0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U, 0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U, 0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U, 0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU, 0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U, 0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU, 0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU, 0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU, 0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU, 0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U, 0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U, 0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U, 0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U, 0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U, 0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU, 0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U, 0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U, 0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U, 0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU, 0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U, 0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU, 0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU, 0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU, 0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU, 0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U, 0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U, 0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U, 0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U, 0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U, 0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U, 0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U, 0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U, 0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U, 0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U, 0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU, 0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU, 0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U, 0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU, 0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU, 0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U, 0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU, 0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U, 0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU, 0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U, 0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU, 0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU, 0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U, 0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U, 0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U, 0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U, 0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU, 0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU, 0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U, 0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU, 0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU, 0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U, 0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU, 0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU, 0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U, 0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U, 0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU, 0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U, 0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U, 0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU, 0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU, 0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U, 0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU, 0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U, 0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU, 0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU, 0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U, 0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU, 0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U, 0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU, 0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U, 0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U, 0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U, 0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U, 0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U, 0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U, 0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U, 0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU, 0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U, 0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U, 0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU, 0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U, 0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU, 0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U, 0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU, 0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU, 0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU, 0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U, 0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U, 0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU, 0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU, 0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U, 0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U, 0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U, 0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU, 0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U, 0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU, 0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U, 0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU, 0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U, 0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU, 0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U, 0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U, 0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U, 0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U, 0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U, 0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU, 0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U, 0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U, 0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U, 0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U, 0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U, 0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU, 0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU, 0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U, 0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U, 0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U, 0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U, 0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U, 0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU, 0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU, 0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU, 0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU, }; const uint64_t kPower10MantissaLowTable[] = { 0x113faa2906a13b3fU, 0x4ac7ca59a424c507U, 0x5d79bcf00d2df649U, 0xf4d82c2c107973dcU, 0x79071b9b8a4be869U, 0x9748e2826cdee284U, 0xfd1b1b2308169b25U, 0xfe30f0f5e50e20f7U, 0xbdbd2d335e51a935U, 0xad2c788035e61382U, 0x4c3bcb5021afcc31U, 0xdf4abe242a1bbf3dU, 0xd71d6dad34a2af0dU, 0x8672648c40e5ad68U, 0x680efdaf511f18c2U, 0x0212bd1b2566def2U, 0x014bb630f7604b57U, 0x419ea3bd35385e2dU, 0x52064cac828675b9U, 0x7343efebd1940993U, 0x1014ebe6c5f90bf8U, 0xd41a26e077774ef6U, 0x8920b098955522b4U, 0x55b46e5f5d5535b0U, 0xeb2189f734aa831dU, 0xa5e9ec7501d523e4U, 0x47b233c92125366eU, 0x999ec0bb696e840aU, 0xc00670ea43ca250dU, 0x380406926a5e5728U, 0xc605083704f5ecf2U, 0xf7864a44c633682eU, 0x7ab3ee6afbe0211dU, 0x5960ea05bad82964U, 0x6fb92487298e33bdU, 0xa5d3b6d479f8e056U, 0x8f48a4899877186cU, 0x331acdabfe94de87U, 0x9ff0c08b7f1d0b14U, 0x07ecf0ae5ee44dd9U, 0xc9e82cd9f69d6150U, 0xbe311c083a225cd2U, 0x6dbd630a48aaf406U, 0x092cbbccdad5b108U, 0x25bbf56008c58ea5U, 0xaf2af2b80af6f24eU, 0x1af5af660db4aee1U, 0x50d98d9fc890ed4dU, 0xe50ff107bab528a0U, 0x1e53ed49a96272c8U, 0x25e8e89c13bb0f7aU, 0x77b191618c54e9acU, 0xd59df5b9ef6a2417U, 0x4b0573286b44ad1dU, 0x4ee367f9430aec32U, 0x229c41f793cda73fU, 0x6b43527578c1110fU, 0x830a13896b78aaa9U, 0x23cc986bc656d553U, 0x2cbfbe86b7ec8aa8U, 0x7bf7d71432f3d6a9U, 0xdaf5ccd93fb0cc53U, 0xd1b3400f8f9cff68U, 0x23100809b9c21fa1U, 0xabd40a0c2832a78aU, 0x16c90c8f323f516cU, 0xae3da7d97f6792e3U, 0x99cd11cfdf41779cU, 0x40405643d711d583U, 0x482835ea666b2572U, 0xda3243650005eecfU, 0x90bed43e40076a82U, 0x5a7744a6e804a291U, 0x711515d0a205cb36U, 0x0d5a5b44ca873e03U, 0xe858790afe9486c2U, 0x626e974dbe39a872U, 0xfb0a3d212dc8128fU, 0x7ce66634bc9d0b99U, 0x1c1fffc1ebc44e80U, 0xa327ffb266b56220U, 0x4bf1ff9f0062baa8U, 0x6f773fc3603db4a9U, 0xcb550fb4384d21d3U, 0x7e2a53a146606a48U, 0x2eda7444cbfc426dU, 0xfa911155fefb5308U, 0x793555ab7eba27caU, 0x4bc1558b2f3458deU, 0x9eb1aaedfb016f16U, 0x465e15a979c1cadcU, 0x0bfacd89ec191ec9U, 0xcef980ec671f667bU, 0x82b7e12780e7401aU, 0xd1b2ecb8b0908810U, 0x861fa7e6dcb4aa15U, 0x67a791e093e1d49aU, 0xe0c8bb2c5c6d24e0U, 0x58fae9f773886e18U, 0xaf39a475506a899eU, 0x6d8406c952429603U, 0xc8e5087ba6d33b83U, 0xfb1e4a9a90880a64U, 0x5cf2eea09a55067fU, 0xf42faa48c0ea481eU, 0xf13b94daf124da26U, 0x76c53d08d6b70858U, 0x54768c4b0c64ca6eU, 0xa9942f5dcf7dfd09U, 0xd3f93b35435d7c4cU, 0xc47bc5014a1a6dafU, 0x359ab6419ca1091bU, 0xc30163d203c94b62U, 0x79e0de63425dcf1dU, 0x985915fc12f542e4U, 0x3e6f5b7b17b2939dU, 0xa705992ceecf9c42U, 0x50c6ff782a838353U, 0xa4f8bf5635246428U, 0x871b7795e136be99U, 0x28e2557b59846e3fU, 0x331aeada2fe589cfU, 0x3ff0d2c85def7621U, 0x0fed077a756b53a9U, 0xd3e8495912c62894U, 0x64712dd7abbbd95cU, 0xbd8d794d96aacfb3U, 0xecf0d7a0fc5583a0U, 0xf41686c49db57244U, 0x311c2875c522ced5U, 0x7d633293366b828bU, 0xae5dff9c02033197U, 0xd9f57f830283fdfcU, 0xd072df63c324fd7bU, 0x4247cb9e59f71e6dU, 0x52d9be85f074e608U, 0x67902e276c921f8bU, 0x00ba1cd8a3db53b6U, 0x80e8a40eccd228a4U, 0x6122cd128006b2cdU, 0x796b805720085f81U, 0xcbe3303674053bb0U, 0xbedbfc4411068a9cU, 0xee92fb5515482d44U, 0x751bdd152d4d1c4aU, 0xd262d45a78a0635dU, 0x86fb897116c87c34U, 0xd45d35e6ae3d4da0U, 0x8974836059cca109U, 0x2bd1a438703fc94bU, 0x7b6306a34627ddcfU, 0x1a3bc84c17b1d542U, 0x20caba5f1d9e4a93U, 0x547eb47b7282ee9cU, 0xe99e619a4f23aa43U, 0x6405fa00e2ec94d4U, 0xde83bc408dd3dd04U, 0x9624ab50b148d445U, 0x3badd624dd9b0957U, 0xe54ca5d70a80e5d6U, 0x5e9fcf4ccd211f4cU, 0x7647c3200069671fU, 0x29ecd9f40041e073U, 0xf468107100525890U, 0x7182148d4066eeb4U, 0xc6f14cd848405530U, 0xb8ada00e5a506a7cU, 0xa6d90811f0e4851cU, 0x908f4a166d1da663U, 0x9a598e4e043287feU, 0x40eff1e1853f29fdU, 0xd12bee59e68ef47cU, 0x82bb74f8301958ceU, 0xe36a52363c1faf01U, 0xdc44e6c3cb279ac1U, 0x29ab103a5ef8c0b9U, 0x7415d448f6b6f0e7U, 0x111b495b3464ad21U, 0xcab10dd900beec34U, 0x3d5d514f40eea742U, 0x0cb4a5a3112a5112U, 0x47f0e785eaba72abU, 0x59ed216765690f56U, 0x306869c13ec3532cU, 0x1e414218c73a13fbU, 0xe5d1929ef90898faU, 0xdf45f746b74abf39U, 0x6b8bba8c328eb783U, 0x066ea92f3f326564U, 0xc80a537b0efefebdU, 0xbd06742ce95f5f36U, 0x2c48113823b73704U, 0xf75a15862ca504c5U, 0x9a984d73dbe722fbU, 0xc13e60d0d2e0ebbaU, 0x318df905079926a8U, 0xfdf17746497f7052U, 0xfeb6ea8bedefa633U, 0xfe64a52ee96b8fc0U, 0x3dfdce7aa3c673b0U, 0x06bea10ca65c084eU, 0x486e494fcff30a62U, 0x5a89dba3c3efccfaU, 0xf89629465a75e01cU, 0xf6bbb397f1135823U, 0x746aa07ded582e2cU, 0xa8c2a44eb4571cdcU, 0x92f34d62616ce413U, 0x77b020baf9c81d17U, 0x0ace1474dc1d122eU, 0x0d819992132456baU, 0x10e1fff697ed6c69U, 0xca8d3ffa1ef463c1U, 0xbd308ff8a6b17cb2U, 0xac7cb3f6d05ddbdeU, 0x6bcdf07a423aa96bU, 0x86c16c98d2c953c6U, 0xe871c7bf077ba8b7U, 0x11471cd764ad4972U, 0xd598e40d3dd89bcfU, 0x4aff1d108d4ec2c3U, 0xcedf722a585139baU, 0xc2974eb4ee658828U, 0x733d226229feea32U, 0x0806357d5a3f525fU, 0xca07c2dcb0cf26f7U, 0xfc89b393dd02f0b5U, 0xbbac2078d443ace2U, 0xd54b944b84aa4c0dU, 0x0a9e795e65d4df11U, 0x4d4617b5ff4a16d5U, 0x504bced1bf8e4e45U, 0xe45ec2862f71e1d6U, 0x5d767327bb4e5a4cU, 0x3a6a07f8d510f86fU, 0x890489f70a55368bU, 0x2b45ac74ccea842eU, 0x3b0b8bc90012929dU, 0x09ce6ebb40173744U, 0xcc420a6a101d0515U, 0x9fa946824a12232dU, 0x47939822dc96abf9U, 0x59787e2b93bc56f7U, 0x57eb4edb3c55b65aU, 0xede622920b6b23f1U, 0xe95fab368e45ecedU, 0x11dbcb0218ebb414U, 0xd652bdc29f26a119U, 0x4be76d3346f0495fU, 0x6f70a4400c562ddbU, 0xcb4ccd500f6bb952U, 0x7e2000a41346a7a7U, 0x8ed400668c0c28c8U, 0x728900802f0f32faU, 0x4f2b40a03ad2ffb9U, 0xe2f610c84987bfa8U, 0x0dd9ca7d2df4d7c9U, 0x91503d1c79720dbbU, 0x75a44c6397ce912aU, 0xc986afbe3ee11abaU, 0xfbe85badce996168U, 0xfae27299423fb9c3U, 0xdccd879fc967d41aU, 0x5400e987bbc1c920U, 0x290123e9aab23b68U, 0xf9a0b6720aaf6521U, 0xf808e40e8d5b3e69U, 0xb60b1d1230b20e04U, 0xb1c6f22b5e6f48c2U, 0x1e38aeb6360b1af3U, 0x25c6da63c38de1b0U, 0x579c487e5a38ad0eU, 0x2d835a9df0c6d851U, 0xf8e431456cf88e65U, 0x1b8e9ecb641b58ffU, 0xe272467e3d222f3fU, 0x5b0ed81dcc6abb0fU, 0x98e947129fc2b4e9U, 0x3f2398d747b36224U, 0x8eec7f0d19a03aadU, 0x1953cf68300424acU, 0x5fa8c3423c052dd7U, 0x3792f412cb06794dU, 0xe2bbd88bbee40bd0U, 0x5b6aceaeae9d0ec4U, 0xf245825a5a445275U, 0xeed6e2f0f0d56712U, 0x55464dd69685606bU, 0xaa97e14c3c26b886U, 0xd53dd99f4b3066a8U, 0xe546a8038efe4029U, 0xde98520472bdd033U, 0x963e66858f6d4440U, 0xdde7001379a44aa8U, 0x5560c018580d5d52U, 0xaab8f01e6e10b4a6U, 0xcab3961304ca70e8U, 0x3d607b97c5fd0d22U, 0x8cb89a7db77c506aU, 0x77f3608e92adb242U, 0x55f038b237591ed3U, 0x6b6c46dec52f6688U, 0x2323ac4b3b3da015U, 0xabec975e0a0d081aU, 0x96e7bd358c904a21U, 0x7e50d64177da2e54U, 0xdde50bd1d5d0b9e9U, 0x955e4ec64b44e864U, 0xbd5af13bef0b113eU, 0xecb1ad8aeacdd58eU, 0x67de18eda5814af2U, 0x80eacf948770ced7U, 0xa1258379a94d028dU, 0x096ee45813a04330U, 0x8bca9d6e188853fcU, 0x775ea264cf55347dU, 0x95364afe032a819dU, 0x3a83ddbd83f52204U, 0xc4926a9672793542U, 0x75b7053c0f178293U, 0x5324c68b12dd6338U, 0xd3f6fc16ebca5e03U, 0x88f4bb1ca6bcf584U, 0x2b31e9e3d06c32e5U, 0x3aff322e62439fcfU, 0x09befeb9fad487c2U, 0x4c2ebe687989a9b3U, 0x0f9d37014bf60a10U, 0x538484c19ef38c94U, 0x2865a5f206b06fb9U, 0xf93f87b7442e45d3U, 0xf78f69a51539d748U, 0xb573440e5a884d1bU, 0x31680a88f8953030U, 0xfdc20d2b36ba7c3dU, 0x3d32907604691b4cU, 0xa63f9a49c2c1b10fU, 0x0fcf80dc33721d53U, 0xd3c36113404ea4a8U, 0x645a1cac083126e9U, 0x3d70a3d70a3d70a3U, 0xccccccccccccccccU, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x0000000000000000U, 0x4000000000000000U, 0x5000000000000000U, 0xa400000000000000U, 0x4d00000000000000U, 0xf020000000000000U, 0x6c28000000000000U, 0xc732000000000000U, 0x3c7f400000000000U, 0x4b9f100000000000U, 0x1e86d40000000000U, 0x1314448000000000U, 0x17d955a000000000U, 0x5dcfab0800000000U, 0x5aa1cae500000000U, 0xf14a3d9e40000000U, 0x6d9ccd05d0000000U, 0xe4820023a2000000U, 0xdda2802c8a800000U, 0xd50b2037ad200000U, 0x4526f422cc340000U, 0x9670b12b7f410000U, 0x3c0cdd765f114000U, 0xa5880a69fb6ac800U, 0x8eea0d047a457a00U, 0x72a4904598d6d880U, 0x47a6da2b7f864750U, 0x999090b65f67d924U, 0xfff4b4e3f741cf6dU, 0xbff8f10e7a8921a4U, 0xaff72d52192b6a0dU, 0x9bf4f8a69f764490U, 0x02f236d04753d5b4U, 0x01d762422c946590U, 0x424d3ad2b7b97ef5U, 0xd2e0898765a7deb2U, 0x63cc55f49f88eb2fU, 0x3cbf6b71c76b25fbU, 0x8bef464e3945ef7aU, 0x97758bf0e3cbb5acU, 0x3d52eeed1cbea317U, 0x4ca7aaa863ee4bddU, 0x8fe8caa93e74ef6aU, 0xb3e2fd538e122b44U, 0x60dbbca87196b616U, 0xbc8955e946fe31cdU, 0x6babab6398bdbe41U, 0xc696963c7eed2dd1U, 0xfc1e1de5cf543ca2U, 0x3b25a55f43294bcbU, 0x49ef0eb713f39ebeU, 0x6e3569326c784337U, 0x49c2c37f07965404U, 0xdc33745ec97be906U, 0x69a028bb3ded71a3U, 0xc40832ea0d68ce0cU, 0xf50a3fa490c30190U, 0x792667c6da79e0faU, 0x577001b891185938U, 0xed4c0226b55e6f86U, 0x544f8158315b05b4U, 0x696361ae3db1c721U, 0x03bc3a19cd1e38e9U, 0x04ab48a04065c723U, 0x62eb0d64283f9c76U, 0x3ba5d0bd324f8394U, 0xca8f44ec7ee36479U, 0x7e998b13cf4e1ecbU, 0x9e3fedd8c321a67eU, 0xc5cfe94ef3ea101eU, 0xbba1f1d158724a12U, 0x2a8a6e45ae8edc97U, 0xf52d09d71a3293bdU, 0x593c2626705f9c56U, 0x6f8b2fb00c77836cU, 0x0b6dfb9c0f956447U, 0x4724bd4189bd5eacU, 0x58edec91ec2cb657U, 0x2f2967b66737e3edU, 0xbd79e0d20082ee74U, 0xecd8590680a3aa11U, 0xe80e6f4820cc9495U, 0x3109058d147fdcddU, 0xbd4b46f0599fd415U, 0x6c9e18ac7007c91aU, 0x03e2cf6bc604ddb0U, 0x84db8346b786151cU, 0xe612641865679a63U, 0x4fcb7e8f3f60c07eU, 0xe3be5e330f38f09dU, 0x5cadf5bfd3072cc5U, 0x73d9732fc7c8f7f6U, 0x2867e7fddcdd9afaU, 0xb281e1fd541501b8U, 0x1f225a7ca91a4226U, 0x3375788de9b06958U, 0x0052d6b1641c83aeU, 0xc0678c5dbd23a49aU, 0xf840b7ba963646e0U, 0xb650e5a93bc3d898U, 0xa3e51f138ab4cebeU, 0xc66f336c36b10137U, 0xb80b0047445d4184U, 0xa60dc059157491e5U, 0x87c89837ad68db2fU, 0x29babe4598c311fbU, 0xf4296dd6fef3d67aU, 0x1899e4a65f58660cU, 0x5ec05dcff72e7f8fU, 0x76707543f4fa1f73U, 0x6a06494a791c53a8U, 0x0487db9d17636892U, 0x45a9d2845d3c42b6U, 0x0b8a2392ba45a9b2U, 0x8e6cac7768d7141eU, 0x3207d795430cd926U, 0x7f44e6bd49e807b8U, 0x5f16206c9c6209a6U, 0x36dba887c37a8c0fU, 0xc2494954da2c9789U, 0xf2db9baa10b7bd6cU, 0x6f92829494e5acc7U, 0xcb772339ba1f17f9U, 0xff2a760414536efbU, 0xfef5138519684abaU, 0x7eb258665fc25d69U, 0xef2f773ffbd97a61U, 0xaafb550ffacfd8faU, 0x95ba2a53f983cf38U, 0xdd945a747bf26183U, 0x94f971119aeef9e4U, 0x7a37cd5601aab85dU, 0xac62e055c10ab33aU, 0x577b986b314d6009U, 0xed5a7e85fda0b80bU, 0x14588f13be847307U, 0x596eb2d8ae258fc8U, 0x6fca5f8ed9aef3bbU, 0x25de7bb9480d5854U, 0xaf561aa79a10ae6aU, 0x1b2ba1518094da04U, 0x90fb44d2f05d0842U, 0x353a1607ac744a53U, 0x42889b8997915ce8U, 0x69956135febada11U, 0x43fab9837e699095U, 0x94f967e45e03f4bbU, 0x1d1be0eebac278f5U, 0x6462d92a69731732U, 0x7d7b8f7503cfdcfeU, 0x5cda735244c3d43eU, 0x3a0888136afa64a7U, 0x088aaa1845b8fdd0U, 0x8aad549e57273d45U, 0x36ac54e2f678864bU, 0x84576a1bb416a7ddU, 0x656d44a2a11c51d5U, 0x9f644ae5a4b1b325U, 0x873d5d9f0dde1feeU, 0xa90cb506d155a7eaU, 0x09a7f12442d588f2U, 0x0c11ed6d538aeb2fU, 0x8f1668c8a86da5faU, 0xf96e017d694487bcU, 0x37c981dcc395a9acU, 0x85bbe253f47b1417U, 0x93956d7478ccec8eU, 0x387ac8d1970027b2U, 0x06997b05fcc0319eU, 0x441fece3bdf81f03U, 0xd527e81cad7626c3U, 0x8a71e223d8d3b074U, 0xf6872d5667844e49U, 0xb428f8ac016561dbU, 0xe13336d701beba52U, 0xecc0024661173473U, 0x27f002d7f95d0190U, 0x31ec038df7b441f4U, 0x7e67047175a15271U, 0x0f0062c6e984d386U, 0x52c07b78a3e60868U, 0xa7709a56ccdf8a82U, 0x88a66076400bb691U, 0x6acff893d00ea435U, 0x0583f6b8c4124d43U, 0xc3727a337a8b704aU, 0x744f18c0592e4c5cU, 0x1162def06f79df73U, 0x8addcb5645ac2ba8U, 0x6d953e2bd7173692U, 0xc8fa8db6ccdd0437U, 0x1d9c9892400a22a2U, 0x2503beb6d00cab4bU, 0x2e44ae64840fd61dU, 0x5ceaecfed289e5d2U, 0x7425a83e872c5f47U, 0xd12f124e28f77719U, 0x82bd6b70d99aaa6fU, 0x636cc64d1001550bU, 0x3c47f7e05401aa4eU, 0x65acfaec34810a71U, 0x7f1839a741a14d0dU, 0x1ede48111209a050U, 0x934aed0aab460432U, 0xf81da84d5617853fU, 0x36251260ab9d668eU, 0xc1d72b7c6b426019U, 0xb24cf65b8612f81fU, 0xdee033f26797b627U, 0x169840ef017da3b1U, 0x8e1f289560ee864eU, 0xf1a6f2bab92a27e2U, 0xae10af696774b1dbU, 0xacca6da1e0a8ef29U, 0x17fd090a58d32af3U, 0xddfc4b4cef07f5b0U, 0x4abdaf101564f98eU, 0x9d6d1ad41abe37f1U, 0x84c86189216dc5edU, 0x32fd3cf5b4e49bb4U, 0x3fbc8c33221dc2a1U, 0x0fabaf3feaa5334aU, 0x29cb4d87f2a7400eU, 0x743e20e9ef511012U, 0x914da9246b255416U, 0x1ad089b6c2f7548eU, 0xa184ac2473b529b1U, 0xc9e5d72d90a2741eU, 0x7e2fa67c7a658892U, 0xddbb901b98feeab7U, 0x552a74227f3ea565U, 0xd53a88958f87275fU, 0x8a892abaf368f137U, 0x2d2b7569b0432d85U, 0x9c3b29620e29fc73U, 0x8349f3ba91b47b8fU, 0x241c70a936219a73U, 0xed238cd383aa0110U, 0xf4363804324a40aaU, 0xb143c6053edcd0d5U, 0xdd94b7868e94050aU, 0xca7cf2b4191c8326U, 0xfd1c2f611f63a3f0U, 0xbc633b39673c8cecU, 0xd5be0503e085d813U, 0x4b2d8644d8a74e18U, 0xddf8e7d60ed1219eU, 0xcabb90e5c942b503U, 0x3d6a751f3b936243U, 0x0cc512670a783ad4U, 0x27fb2b80668b24c5U, 0xb1f9f660802dedf6U, 0x5e7873f8a0396973U, 0xdb0b487b6423e1e8U, 0x91ce1a9a3d2cda62U, 0x7641a140cc7810fbU, 0xa9e904c87fcb0a9dU, 0x546345fa9fbdcd44U, 0xa97c177947ad4095U, 0x49ed8eabcccc485dU, 0x5c68f256bfff5a74U, 0x73832eec6fff3111U, 0xc831fd53c5ff7eabU, 0xba3e7ca8b77f5e55U, 0x28ce1bd2e55f35ebU, 0x7980d163cf5b81b3U, 0xd7e105bcc332621fU, 0x8dd9472bf3fefaa7U, 0xb14f98f6f0feb951U, 0x6ed1bf9a569f33d3U, 0x0a862f80ec4700c8U, 0xcd27bb612758c0faU, 0x8038d51cb897789cU, 0xe0470a63e6bd56c3U, 0x1858ccfce06cac74U, 0x0f37801e0c43ebc8U, 0xd30560258f54e6baU, 0x47c6b82ef32a2069U, 0x4cdc331d57fa5441U, 0xe0133fe4adf8e952U, 0x58180fddd97723a6U, 0x570f09eaa7ea7648U, }; } // namespace ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/cord_buffer.cc0000644000175000017510000000162014737212474022620 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/cord_buffer.h" #include #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr size_t CordBuffer::kDefaultLimit; constexpr size_t CordBuffer::kCustomLimit; #endif ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/numbers.cc0000644000175000017510000012247014737212474022022 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This file contains string processing functions related to // numeric values. #include "absl/strings/numbers.h" #include #include #include // for DBL_DIG and FLT_DIG #include // for HUGE_VAL #include #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/strings/ascii.h" #include "absl/strings/charconv.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/memutil.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" namespace absl { ABSL_NAMESPACE_BEGIN bool SimpleAtof(absl::string_view str, float* out) { *out = 0.0; str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one // is present, skip it, while avoiding accepting "+-0" as valid. if (!str.empty() && str[0] == '+') { str.remove_prefix(1); if (!str.empty() && str[0] == '-') { return false; } } auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } if (result.ptr != str.data() + str.size()) { // not all non-whitespace characters consumed return false; } // from_chars() with DR 3081's current wording will return max() on // overflow. SimpleAtof returns infinity instead. if (result.ec == std::errc::result_out_of_range) { if (*out > 1.0) { *out = std::numeric_limits::infinity(); } else if (*out < -1.0) { *out = -std::numeric_limits::infinity(); } } return true; } bool SimpleAtod(absl::string_view str, double* out) { *out = 0.0; str = StripAsciiWhitespace(str); // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one // is present, skip it, while avoiding accepting "+-0" as valid. if (!str.empty() && str[0] == '+') { str.remove_prefix(1); if (!str.empty() && str[0] == '-') { return false; } } auto result = absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { return false; } if (result.ptr != str.data() + str.size()) { // not all non-whitespace characters consumed return false; } // from_chars() with DR 3081's current wording will return max() on // overflow. SimpleAtod returns infinity instead. if (result.ec == std::errc::result_out_of_range) { if (*out > 1.0) { *out = std::numeric_limits::infinity(); } else if (*out < -1.0) { *out = -std::numeric_limits::infinity(); } } return true; } bool SimpleAtob(absl::string_view str, bool* out) { ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr."); if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") || EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") || EqualsIgnoreCase(str, "1")) { *out = true; return true; } if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") || EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") || EqualsIgnoreCase(str, "0")) { *out = false; return true; } return false; } // ---------------------------------------------------------------------- // FastIntToBuffer() overloads // // Like the Fast*ToBuffer() functions above, these are intended for speed. // Unlike the Fast*ToBuffer() functions, however, these functions write // their output to the beginning of the buffer. The caller is responsible // for ensuring that the buffer has enough space to hold the output. // // Returns a pointer to the end of the string (i.e. the null character // terminating the string). // ---------------------------------------------------------------------- namespace { // Various routines to encode integers to strings. // We split data encodings into a group of 2 digits, 4 digits, 8 digits as // it's easier to combine powers of two into scalar arithmetic. // Previous implementation used a lookup table of 200 bytes for every 2 bytes // and it was memory bound, any L1 cache miss would result in a much slower // result. When benchmarking with a cache eviction rate of several percent, // this implementation proved to be better. // These constants represent '00', '0000' and '00000000' as ascii strings in // integers. We can add these numbers if we encode to bytes from 0 to 9. as // 'i' = '0' + i for 0 <= i <= 9. constexpr uint32_t kTwoZeroBytes = 0x0101 * '0'; constexpr uint64_t kFourZeroBytes = 0x01010101 * '0'; constexpr uint64_t kEightZeroBytes = 0x0101010101010101ull * '0'; // * 103 / 1024 is a division by 10 for values from 0 to 99. It's also a // division of a structure [k takes 2 bytes][m takes 2 bytes], then * 103 / 1024 // will be [k / 10][m / 10]. It allows parallel division. constexpr uint64_t kDivisionBy10Mul = 103u; constexpr uint64_t kDivisionBy10Div = 1 << 10; // * 10486 / 1048576 is a division by 100 for values from 0 to 9999. constexpr uint64_t kDivisionBy100Mul = 10486u; constexpr uint64_t kDivisionBy100Div = 1 << 20; // Encode functions write the ASCII output of input `n` to `out_str`. inline char* EncodeHundred(uint32_t n, char* out_str) { int num_digits = static_cast(n - 10) >> 8; uint32_t base = kTwoZeroBytes; uint32_t div10 = (n * kDivisionBy10Mul) / kDivisionBy10Div; uint32_t mod10 = n - 10u * div10; base += div10 + (mod10 << 8); base >>= num_digits & 8; little_endian::Store16(out_str, static_cast(base)); return out_str + 2 + num_digits; } inline char* EncodeTenThousand(uint32_t n, char* out_str) { // We split lower 2 digits and upper 2 digits of n into 2 byte consecutive // blocks. 123 -> [\0\1][\0\23]. We divide by 10 both blocks // (it's 1 division + zeroing upper bits), and compute modulo 10 as well "in // parallel". Then we combine both results to have both ASCII digits, // strip trailing zeros, add ASCII '0000' and return. uint32_t div100 = (n * kDivisionBy100Mul) / kDivisionBy100Div; uint32_t mod100 = n - 100ull * div100; uint32_t hundreds = (mod100 << 16) + div100; uint32_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div; tens &= (0xFull << 16) | 0xFull; tens += (hundreds - 10ull * tens) << 8; ABSL_ASSUME(tens != 0); // The result can contain trailing zero bits, we need to strip them to a first // significant byte in a final representation. For example, for n = 123, we // have tens to have representation \0\1\2\3. We do `& -8` to round // to a multiple to 8 to strip zero bytes, not all zero bits. // countr_zero to help. // 0 minus 8 to make MSVC happy. uint32_t zeroes = static_cast(absl::countr_zero(tens)) & (0 - 8ull); tens += kFourZeroBytes; tens >>= zeroes; little_endian::Store32(out_str, tens); return out_str + sizeof(tens) - zeroes / 8; } // Prepare functions return an integer that should be written to out_str // (but possibly include trailing zeros). // For hi < 10000, lo < 10000 returns uint64_t as encoded in ASCII with // possibly trailing zeroes of the number hi * 10000 + lo. inline uint64_t PrepareTenThousands(uint64_t hi, uint64_t lo) { uint64_t merged = hi | (lo << 32); uint64_t div100 = ((merged * kDivisionBy100Mul) / kDivisionBy100Div) & ((0x7Full << 32) | 0x7Full); uint64_t mod100 = merged - 100ull * div100; uint64_t hundreds = (mod100 << 16) + div100; uint64_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div; tens &= (0xFull << 48) | (0xFull << 32) | (0xFull << 16) | 0xFull; tens += (hundreds - 10ull * tens) << 8; return tens; } inline char* EncodeFullU32(uint32_t n, char* out_str) { if (n < 100'000'000) { uint64_t bottom = PrepareTenThousands(n / 10000, n % 10000); ABSL_ASSUME(bottom != 0); // 0 minus 8 to make MSVC happy. uint32_t zeroes = static_cast(absl::countr_zero(bottom)) & (0 - 8ull); uint64_t bottom_res = bottom + kEightZeroBytes; bottom_res >>= zeroes; little_endian::Store64(out_str, bottom_res); return out_str + sizeof(bottom) - zeroes / 8; } uint32_t top = n / 100'000'000; n %= 100'000'000; uint64_t bottom = PrepareTenThousands(n / 10000, n % 10000); uint64_t bottom_res = bottom + kEightZeroBytes; out_str = EncodeHundred(top, out_str); little_endian::Store64(out_str, bottom_res); return out_str + sizeof(bottom); } } // namespace void numbers_internal::PutTwoDigits(uint32_t i, char* buf) { assert(i < 100); uint32_t base = kTwoZeroBytes; uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div; uint32_t mod10 = i - 10u * div10; base += div10 + (mod10 << 8); little_endian::Store16(buf, static_cast(base)); } char* numbers_internal::FastIntToBuffer(uint32_t n, char* out_str) { if (n < 100) { out_str = EncodeHundred(n, out_str); goto set_last_zero; } if (n < 10000) { out_str = EncodeTenThousand(n, out_str); goto set_last_zero; } out_str = EncodeFullU32(n, out_str); set_last_zero: *out_str = '\0'; return out_str; } char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { uint32_t u = static_cast(i); if (i < 0) { *buffer++ = '-'; // We need to do the negation in modular (i.e., "unsigned") // arithmetic; MSVC++ apparently warns for plain "-u", so // we write the equivalent expression "0 - u" instead. u = 0 - u; } return numbers_internal::FastIntToBuffer(u, buffer); } char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { uint32_t u32 = static_cast(i); if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer); // 10**9 < 2**32 <= i < 10**10, we can do 2+8 uint64_t div08 = i / 100'000'000ull; uint64_t mod08 = i % 100'000'000ull; uint64_t mod_result = PrepareTenThousands(mod08 / 10000, mod08 % 10000) + kEightZeroBytes; if (i < 10'000'000'000ull) { buffer = EncodeHundred(static_cast(div08), buffer); little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } // i < 10**16, in this case 8+8 if (i < 10'000'000'000'000'000ull) { buffer = EncodeFullU32(static_cast(div08), buffer); little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } else { // 4 + 8 + 8 uint64_t div016 = i / 10'000'000'000'000'000ull; buffer = EncodeTenThousand(static_cast(div016), buffer); uint64_t mid_result = div08 - div016 * 100'000'000ull; mid_result = PrepareTenThousands(mid_result / 10000, mid_result % 10000) + kEightZeroBytes; little_endian::Store64(buffer, mid_result); buffer += 8; little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } set_last_zero: *buffer = '\0'; return buffer; } char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { uint64_t u = static_cast(i); if (i < 0) { *buffer++ = '-'; u = 0 - u; } return numbers_internal::FastIntToBuffer(u, buffer); } // Given a 128-bit number expressed as a pair of uint64_t, high half first, // return that number multiplied by the given 32-bit value. If the result is // too large to fit in a 128-bit number, divide it by 2 until it fits. static std::pair Mul32(std::pair num, uint32_t mul) { uint64_t bits0_31 = num.second & 0xFFFFFFFF; uint64_t bits32_63 = num.second >> 32; uint64_t bits64_95 = num.first & 0xFFFFFFFF; uint64_t bits96_127 = num.first >> 32; // The picture so far: each of these 64-bit values has only the lower 32 bits // filled in. // bits96_127: [ 00000000 xxxxxxxx ] // bits64_95: [ 00000000 xxxxxxxx ] // bits32_63: [ 00000000 xxxxxxxx ] // bits0_31: [ 00000000 xxxxxxxx ] bits0_31 *= mul; bits32_63 *= mul; bits64_95 *= mul; bits96_127 *= mul; // Now the top halves may also have value, though all 64 of their bits will // never be set at the same time, since they are a result of a 32x32 bit // multiply. This makes the carry calculation slightly easier. // bits96_127: [ mmmmmmmm | mmmmmmmm ] // bits64_95: [ | mmmmmmmm mmmmmmmm | ] // bits32_63: | [ mmmmmmmm | mmmmmmmm ] // bits0_31: | [ | mmmmmmmm mmmmmmmm ] // eventually: [ bits128_up | ...bits64_127.... | ..bits0_63... ] uint64_t bits0_63 = bits0_31 + (bits32_63 << 32); uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) + (bits0_63 < bits0_31); uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); if (bits128_up == 0) return {bits64_127, bits0_63}; auto shift = static_cast(bit_width(bits128_up)); uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); return {hi, lo}; } // Compute num * 5 ^ expfive, and return the first 128 bits of the result, // where the first bit is always a one. So PowFive(1, 0) starts 0b100000, // PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc. static std::pair PowFive(uint64_t num, int expfive) { std::pair result = {num, 0}; while (expfive >= 13) { // 5^13 is the highest power of five that will fit in a 32-bit integer. result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5); expfive -= 13; } constexpr uint32_t powers_of_five[13] = { 1, 5, 5 * 5, 5 * 5 * 5, 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; result = Mul32(result, powers_of_five[expfive & 15]); int shift = countl_zero(result.first); if (shift != 0) { result.first = (result.first << shift) + (result.second >> (64 - shift)); result.second = (result.second << shift); } return result; } struct ExpDigits { int32_t exponent; char digits[6]; }; // SplitToSix converts value, a positive double-precision floating-point number, // into a base-10 exponent and 6 ASCII digits, where the first digit is never // zero. For example, SplitToSix(1) returns an exponent of zero and a digits // array of {'1', '0', '0', '0', '0', '0'}. If value is exactly halfway between // two possible representations, e.g. value = 100000.5, then "round to even" is // performed. static ExpDigits SplitToSix(const double value) { ExpDigits exp_dig; int exp = 5; double d = value; // First step: calculate a close approximation of the output, where the // value d will be between 100,000 and 999,999, representing the digits // in the output ASCII array, and exp is the base-10 exponent. It would be // faster to use a table here, and to look up the base-2 exponent of value, // however value is an IEEE-754 64-bit number, so the table would have 2,000 // entries, which is not cache-friendly. if (d >= 999999.5) { if (d >= 1e+261) exp += 256, d *= 1e-256; if (d >= 1e+133) exp += 128, d *= 1e-128; if (d >= 1e+69) exp += 64, d *= 1e-64; if (d >= 1e+37) exp += 32, d *= 1e-32; if (d >= 1e+21) exp += 16, d *= 1e-16; if (d >= 1e+13) exp += 8, d *= 1e-8; if (d >= 1e+9) exp += 4, d *= 1e-4; if (d >= 1e+7) exp += 2, d *= 1e-2; if (d >= 1e+6) exp += 1, d *= 1e-1; } else { if (d < 1e-250) exp -= 256, d *= 1e256; if (d < 1e-122) exp -= 128, d *= 1e128; if (d < 1e-58) exp -= 64, d *= 1e64; if (d < 1e-26) exp -= 32, d *= 1e32; if (d < 1e-10) exp -= 16, d *= 1e16; if (d < 1e-2) exp -= 8, d *= 1e8; if (d < 1e+2) exp -= 4, d *= 1e4; if (d < 1e+4) exp -= 2, d *= 1e2; if (d < 1e+5) exp -= 1, d *= 1e1; } // At this point, d is in the range [99999.5..999999.5) and exp is in the // range [-324..308]. Since we need to round d up, we want to add a half // and truncate. // However, the technique above may have lost some precision, due to its // repeated multiplication by constants that each may be off by half a bit // of precision. This only matters if we're close to the edge though. // Since we'd like to know if the fractional part of d is close to a half, // we multiply it by 65536 and see if the fractional part is close to 32768. // (The number doesn't have to be a power of two,but powers of two are faster) uint64_t d64k = d * 65536; uint32_t dddddd; // A 6-digit decimal integer. if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) { // OK, it's fairly likely that precision was lost above, which is // not a surprise given only 52 mantissa bits are available. Therefore // redo the calculation using 128-bit numbers. (64 bits are not enough). // Start out with digits rounded down; maybe add one below. dddddd = static_cast(d64k / 65536); // mantissa is a 64-bit integer representing M.mmm... * 2^63. The actual // value we're representing, of course, is M.mmm... * 2^exp2. int exp2; double m = std::frexp(value, &exp2); uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0); // std::frexp returns an m value in the range [0.5, 1.0), however we // can't multiply it by 2^64 and convert to an integer because some FPUs // throw an exception when converting an number higher than 2^63 into an // integer - even an unsigned 64-bit integer! Fortunately it doesn't matter // since m only has 52 significant bits anyway. mantissa <<= 1; exp2 -= 64; // not needed, but nice for debugging // OK, we are here to compare: // (dddddd + 0.5) * 10^(exp-5) vs. mantissa * 2^exp2 // so we can round up dddddd if appropriate. Those values span the full // range of 600 orders of magnitude of IEE 64-bit floating-point. // Fortunately, we already know they are very close, so we don't need to // track the base-2 exponent of both sides. This greatly simplifies the // the math since the 2^exp2 calculation is unnecessary and the power-of-10 // calculation can become a power-of-5 instead. std::pair edge, val; if (exp >= 6) { // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa // Since we're tossing powers of two, 2 * dddddd + 1 is the // same as dddddd + 0.5 edge = PowFive(2 * dddddd + 1, exp - 5); val.first = mantissa; val.second = 0; } else { // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did // above because (exp - 5) is negative. So we compare (dddddd + 0.5) to // mantissa * 5 ^ (5 - exp) edge = PowFive(2 * dddddd + 1, 0); val = PowFive(mantissa, 5 - exp); } // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first, // val.second, edge.first, edge.second); if (val > edge) { dddddd++; } else if (val == edge) { dddddd += (dddddd & 1); } } else { // Here, we are not close to the edge. dddddd = static_cast((d64k + 32768) / 65536); } if (dddddd == 1000000) { dddddd = 100000; exp += 1; } exp_dig.exponent = exp; uint32_t two_digits = dddddd / 10000; dddddd -= two_digits * 10000; numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]); two_digits = dddddd / 100; dddddd -= two_digits * 100; numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]); numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]); return exp_dig; } // Helper function for fast formatting of floating-point. // The result is the same as "%g", a.k.a. "%.6g". size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { static_assert(std::numeric_limits::is_iec559, "IEEE-754/IEC-559 support only"); char* out = buffer; // we write data to out, incrementing as we go, but // FloatToBuffer always returns the address of the buffer // passed in. if (std::isnan(d)) { strcpy(out, "nan"); // NOLINT(runtime/printf) return 3; } if (d == 0) { // +0 and -0 are handled here if (std::signbit(d)) *out++ = '-'; *out++ = '0'; *out = 0; return static_cast(out - buffer); } if (d < 0) { *out++ = '-'; d = -d; } if (d > std::numeric_limits::max()) { strcpy(out, "inf"); // NOLINT(runtime/printf) return static_cast(out + 3 - buffer); } auto exp_dig = SplitToSix(d); int exp = exp_dig.exponent; const char* digits = exp_dig.digits; out[0] = '0'; out[1] = '.'; switch (exp) { case 5: memcpy(out, &digits[0], 6), out += 6; *out = 0; return static_cast(out - buffer); case 4: memcpy(out, &digits[0], 5), out += 5; if (digits[5] != '0') { *out++ = '.'; *out++ = digits[5]; } *out = 0; return static_cast(out - buffer); case 3: memcpy(out, &digits[0], 4), out += 4; if ((digits[5] | digits[4]) != '0') { *out++ = '.'; *out++ = digits[4]; if (digits[5] != '0') *out++ = digits[5]; } *out = 0; return static_cast(out - buffer); case 2: memcpy(out, &digits[0], 3), out += 3; *out++ = '.'; memcpy(out, &digits[3], 3); out += 3; while (out[-1] == '0') --out; if (out[-1] == '.') --out; *out = 0; return static_cast(out - buffer); case 1: memcpy(out, &digits[0], 2), out += 2; *out++ = '.'; memcpy(out, &digits[2], 4); out += 4; while (out[-1] == '0') --out; if (out[-1] == '.') --out; *out = 0; return static_cast(out - buffer); case 0: memcpy(out, &digits[0], 1), out += 1; *out++ = '.'; memcpy(out, &digits[1], 5); out += 5; while (out[-1] == '0') --out; if (out[-1] == '.') --out; *out = 0; return static_cast(out - buffer); case -4: out[2] = '0'; ++out; ABSL_FALLTHROUGH_INTENDED; case -3: out[2] = '0'; ++out; ABSL_FALLTHROUGH_INTENDED; case -2: out[2] = '0'; ++out; ABSL_FALLTHROUGH_INTENDED; case -1: out += 2; memcpy(out, &digits[0], 6); out += 6; while (out[-1] == '0') --out; *out = 0; return static_cast(out - buffer); } assert(exp < -4 || exp >= 6); out[0] = digits[0]; assert(out[1] == '.'); out += 2; memcpy(out, &digits[1], 5), out += 5; while (out[-1] == '0') --out; if (out[-1] == '.') --out; *out++ = 'e'; if (exp > 0) { *out++ = '+'; } else { *out++ = '-'; exp = -exp; } if (exp > 99) { int dig1 = exp / 100; exp -= dig1 * 100; *out++ = '0' + static_cast(dig1); } PutTwoDigits(static_cast(exp), out); out += 2; *out = 0; return static_cast(out - buffer); } namespace { // Represents integer values of digits. // Uses 36 to indicate an invalid character since we support // bases up to 36. static const int8_t kAsciiToInt[256] = { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s. 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36}; // Parse the sign and optional hex or oct prefix in text. inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/, int* base_ptr /*inout*/, bool* negative_ptr /*output*/) { if (text->data() == nullptr) { return false; } const char* start = text->data(); const char* end = start + text->size(); int base = *base_ptr; // Consume whitespace. while (start < end && absl::ascii_isspace(static_cast(start[0]))) { ++start; } while (start < end && absl::ascii_isspace(static_cast(end[-1]))) { --end; } if (start >= end) { return false; } // Consume sign. *negative_ptr = (start[0] == '-'); if (*negative_ptr || start[0] == '+') { ++start; if (start >= end) { return false; } } // Consume base-dependent prefix. // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10 // base 16: "0x" -> base 16 // Also validate the base. if (base == 0) { if (end - start >= 2 && start[0] == '0' && (start[1] == 'x' || start[1] == 'X')) { base = 16; start += 2; if (start >= end) { // "0x" with no digits after is invalid. return false; } } else if (end - start >= 1 && start[0] == '0') { base = 8; start += 1; } else { base = 10; } } else if (base == 16) { if (end - start >= 2 && start[0] == '0' && (start[1] == 'x' || start[1] == 'X')) { start += 2; if (start >= end) { // "0x" with no digits after is invalid. return false; } } } else if (base >= 2 && base <= 36) { // okay } else { return false; } *text = absl::string_view(start, static_cast(end - start)); *base_ptr = base; return true; } // Consume digits. // // The classic loop: // // for each digit // value = value * base + digit // value *= sign // // The classic loop needs overflow checking. It also fails on the most // negative integer, -2147483648 in 32-bit two's complement representation. // // My improved loop: // // if (!negative) // for each digit // value = value * base // value = value + digit // else // for each digit // value = value * base // value = value - digit // // Overflow checking becomes simple. // Lookup tables per IntType: // vmax/base and vmin/base are precomputed because division costs at least 8ns. // TODO(junyer): Doing this per base instead (i.e. an array of structs, not a // struct of arrays) would probably be better in terms of d-cache for the most // commonly used bases. template struct LookupTables { ABSL_CONST_INIT static const IntType kVmaxOverBase[]; ABSL_CONST_INIT static const IntType kVminOverBase[]; }; // An array initializer macro for X/base where base in [0, 36]. // However, note that lookups for base in [0, 1] should never happen because // base has been validated to be in [2, 36] by safe_parse_sign_and_base(). #define X_OVER_BASE_INITIALIZER(X) \ { \ 0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \ X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18, \ X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26, \ X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34, \ X / 35, X / 36, \ } // This kVmaxOverBase is generated with // for (int base = 2; base < 37; ++base) { // absl::uint128 max = std::numeric_limits::max(); // auto result = max / base; // std::cout << " MakeUint128(" << absl::Uint128High64(result) << "u, " // << absl::Uint128Low64(result) << "u),\n"; // } // See https://godbolt.org/z/aneYsb // // uint128& operator/=(uint128) is not constexpr, so hardcode the resulting // array to avoid a static initializer. template <> ABSL_CONST_INIT const uint128 LookupTables::kVmaxOverBase[] = { 0, 0, MakeUint128(9223372036854775807u, 18446744073709551615u), MakeUint128(6148914691236517205u, 6148914691236517205u), MakeUint128(4611686018427387903u, 18446744073709551615u), MakeUint128(3689348814741910323u, 3689348814741910323u), MakeUint128(3074457345618258602u, 12297829382473034410u), MakeUint128(2635249153387078802u, 5270498306774157604u), MakeUint128(2305843009213693951u, 18446744073709551615u), MakeUint128(2049638230412172401u, 14347467612885206812u), MakeUint128(1844674407370955161u, 11068046444225730969u), MakeUint128(1676976733973595601u, 8384883669867978007u), MakeUint128(1537228672809129301u, 6148914691236517205u), MakeUint128(1418980313362273201u, 4256940940086819603u), MakeUint128(1317624576693539401u, 2635249153387078802u), MakeUint128(1229782938247303441u, 1229782938247303441u), MakeUint128(1152921504606846975u, 18446744073709551615u), MakeUint128(1085102592571150095u, 1085102592571150095u), MakeUint128(1024819115206086200u, 16397105843297379214u), MakeUint128(970881267037344821u, 16504981539634861972u), MakeUint128(922337203685477580u, 14757395258967641292u), MakeUint128(878416384462359600u, 14054662151397753612u), MakeUint128(838488366986797800u, 13415813871788764811u), MakeUint128(802032351030850070u, 4812194106185100421u), MakeUint128(768614336404564650u, 12297829382473034410u), MakeUint128(737869762948382064u, 11805916207174113034u), MakeUint128(709490156681136600u, 11351842506898185609u), MakeUint128(683212743470724133u, 17080318586768103348u), MakeUint128(658812288346769700u, 10540996613548315209u), MakeUint128(636094623231363848u, 15266270957552732371u), MakeUint128(614891469123651720u, 9838263505978427528u), MakeUint128(595056260442243600u, 9520900167075897608u), MakeUint128(576460752303423487u, 18446744073709551615u), MakeUint128(558992244657865200u, 8943875914525843207u), MakeUint128(542551296285575047u, 9765923333140350855u), MakeUint128(527049830677415760u, 8432797290838652167u), MakeUint128(512409557603043100u, 8198552921648689607u), }; // This kVmaxOverBase generated with // for (int base = 2; base < 37; ++base) { // absl::int128 max = std::numeric_limits::max(); // auto result = max / base; // std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", " // << absl::Int128Low64(result) << "u),\n"; // } // See https://godbolt.org/z/7djYWz // // int128& operator/=(int128) is not constexpr, so hardcode the resulting array // to avoid a static initializer. template <> ABSL_CONST_INIT const int128 LookupTables::kVmaxOverBase[] = { 0, 0, MakeInt128(4611686018427387903, 18446744073709551615u), MakeInt128(3074457345618258602, 12297829382473034410u), MakeInt128(2305843009213693951, 18446744073709551615u), MakeInt128(1844674407370955161, 11068046444225730969u), MakeInt128(1537228672809129301, 6148914691236517205u), MakeInt128(1317624576693539401, 2635249153387078802u), MakeInt128(1152921504606846975, 18446744073709551615u), MakeInt128(1024819115206086200, 16397105843297379214u), MakeInt128(922337203685477580, 14757395258967641292u), MakeInt128(838488366986797800, 13415813871788764811u), MakeInt128(768614336404564650, 12297829382473034410u), MakeInt128(709490156681136600, 11351842506898185609u), MakeInt128(658812288346769700, 10540996613548315209u), MakeInt128(614891469123651720, 9838263505978427528u), MakeInt128(576460752303423487, 18446744073709551615u), MakeInt128(542551296285575047, 9765923333140350855u), MakeInt128(512409557603043100, 8198552921648689607u), MakeInt128(485440633518672410, 17475862806672206794u), MakeInt128(461168601842738790, 7378697629483820646u), MakeInt128(439208192231179800, 7027331075698876806u), MakeInt128(419244183493398900, 6707906935894382405u), MakeInt128(401016175515425035, 2406097053092550210u), MakeInt128(384307168202282325, 6148914691236517205u), MakeInt128(368934881474191032, 5902958103587056517u), MakeInt128(354745078340568300, 5675921253449092804u), MakeInt128(341606371735362066, 17763531330238827482u), MakeInt128(329406144173384850, 5270498306774157604u), MakeInt128(318047311615681924, 7633135478776366185u), MakeInt128(307445734561825860, 4919131752989213764u), MakeInt128(297528130221121800, 4760450083537948804u), MakeInt128(288230376151711743, 18446744073709551615u), MakeInt128(279496122328932600, 4471937957262921603u), MakeInt128(271275648142787523, 14106333703424951235u), MakeInt128(263524915338707880, 4216398645419326083u), MakeInt128(256204778801521550, 4099276460824344803u), }; // This kVminOverBase generated with // for (int base = 2; base < 37; ++base) { // absl::int128 min = std::numeric_limits::min(); // auto result = min / base; // std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", " // << absl::Int128Low64(result) << "u),\n"; // } // // See https://godbolt.org/z/7djYWz // // int128& operator/=(int128) is not constexpr, so hardcode the resulting array // to avoid a static initializer. template <> ABSL_CONST_INIT const int128 LookupTables::kVminOverBase[] = { 0, 0, MakeInt128(-4611686018427387904, 0u), MakeInt128(-3074457345618258603, 6148914691236517206u), MakeInt128(-2305843009213693952, 0u), MakeInt128(-1844674407370955162, 7378697629483820647u), MakeInt128(-1537228672809129302, 12297829382473034411u), MakeInt128(-1317624576693539402, 15811494920322472814u), MakeInt128(-1152921504606846976, 0u), MakeInt128(-1024819115206086201, 2049638230412172402u), MakeInt128(-922337203685477581, 3689348814741910324u), MakeInt128(-838488366986797801, 5030930201920786805u), MakeInt128(-768614336404564651, 6148914691236517206u), MakeInt128(-709490156681136601, 7094901566811366007u), MakeInt128(-658812288346769701, 7905747460161236407u), MakeInt128(-614891469123651721, 8608480567731124088u), MakeInt128(-576460752303423488, 0u), MakeInt128(-542551296285575048, 8680820740569200761u), MakeInt128(-512409557603043101, 10248191152060862009u), MakeInt128(-485440633518672411, 970881267037344822u), MakeInt128(-461168601842738791, 11068046444225730970u), MakeInt128(-439208192231179801, 11419412998010674810u), MakeInt128(-419244183493398901, 11738837137815169211u), MakeInt128(-401016175515425036, 16040647020617001406u), MakeInt128(-384307168202282326, 12297829382473034411u), MakeInt128(-368934881474191033, 12543785970122495099u), MakeInt128(-354745078340568301, 12770822820260458812u), MakeInt128(-341606371735362067, 683212743470724134u), MakeInt128(-329406144173384851, 13176245766935394012u), MakeInt128(-318047311615681925, 10813608594933185431u), MakeInt128(-307445734561825861, 13527612320720337852u), MakeInt128(-297528130221121801, 13686293990171602812u), MakeInt128(-288230376151711744, 0u), MakeInt128(-279496122328932601, 13974806116446630013u), MakeInt128(-271275648142787524, 4340410370284600381u), MakeInt128(-263524915338707881, 14230345428290225533u), MakeInt128(-256204778801521551, 14347467612885206813u), }; template ABSL_CONST_INIT const IntType LookupTables::kVmaxOverBase[] = X_OVER_BASE_INITIALIZER(std::numeric_limits::max()); template ABSL_CONST_INIT const IntType LookupTables::kVminOverBase[] = X_OVER_BASE_INITIALIZER(std::numeric_limits::min()); #undef X_OVER_BASE_INITIALIZER template inline bool safe_parse_positive_int(absl::string_view text, int base, IntType* value_p) { IntType value = 0; const IntType vmax = std::numeric_limits::max(); assert(vmax > 0); assert(base >= 0); const IntType base_inttype = static_cast(base); assert(vmax >= base_inttype); const IntType vmax_over_base = LookupTables::kVmaxOverBase[base]; assert(base < 2 || std::numeric_limits::max() / base_inttype == vmax_over_base); const char* start = text.data(); const char* end = start + text.size(); // loop over digits for (; start < end; ++start) { unsigned char c = static_cast(start[0]); IntType digit = static_cast(kAsciiToInt[c]); if (digit >= base_inttype) { *value_p = value; return false; } if (value > vmax_over_base) { *value_p = vmax; return false; } value *= base_inttype; if (value > vmax - digit) { *value_p = vmax; return false; } value += digit; } *value_p = value; return true; } template inline bool safe_parse_negative_int(absl::string_view text, int base, IntType* value_p) { IntType value = 0; const IntType vmin = std::numeric_limits::min(); assert(vmin < 0); assert(vmin <= 0 - base); IntType vmin_over_base = LookupTables::kVminOverBase[base]; assert(base < 2 || std::numeric_limits::min() / base == vmin_over_base); // 2003 c++ standard [expr.mul] // "... the sign of the remainder is implementation-defined." // Although (vmin/base)*base + vmin%base is always vmin. // 2011 c++ standard tightens the spec but we cannot rely on it. // TODO(junyer): Handle this in the lookup table generation. if (vmin % base > 0) { vmin_over_base += 1; } const char* start = text.data(); const char* end = start + text.size(); // loop over digits for (; start < end; ++start) { unsigned char c = static_cast(start[0]); int digit = kAsciiToInt[c]; if (digit >= base) { *value_p = value; return false; } if (value < vmin_over_base) { *value_p = vmin; return false; } value *= base; if (value < vmin + digit) { *value_p = vmin; return false; } value -= digit; } *value_p = value; return true; } // Input format based on POSIX.1-2008 strtol // http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html template inline bool safe_int_internal(absl::string_view text, IntType* value_p, int base) { *value_p = 0; bool negative; if (!safe_parse_sign_and_base(&text, &base, &negative)) { return false; } if (!negative) { return safe_parse_positive_int(text, base, value_p); } else { return safe_parse_negative_int(text, base, value_p); } } template inline bool safe_uint_internal(absl::string_view text, IntType* value_p, int base) { *value_p = 0; bool negative; if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { return false; } return safe_parse_positive_int(text, base, value_p); } } // anonymous namespace namespace numbers_internal { // Digit conversion. ABSL_CONST_INIT ABSL_DLL const char kHexChar[] = "0123456789abcdef"; ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "000102030405060708090a0b0c0d0e0f" "101112131415161718191a1b1c1d1e1f" "202122232425262728292a2b2c2d2e2f" "303132333435363738393a3b3c3d3e3f" "404142434445464748494a4b4c4d4e4f" "505152535455565758595a5b5c5d5e5f" "606162636465666768696a6b6c6d6e6f" "707172737475767778797a7b7c7d7e7f" "808182838485868788898a8b8c8d8e8f" "909192939495969798999a9b9c9d9e9f" "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; bool safe_strto32_base(absl::string_view text, int32_t* value, int base) { return safe_int_internal(text, value, base); } bool safe_strto64_base(absl::string_view text, int64_t* value, int base) { return safe_int_internal(text, value, base); } bool safe_strto128_base(absl::string_view text, int128* value, int base) { return safe_int_internal(text, value, base); } bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) { return safe_uint_internal(text, value, base); } bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) { return safe_uint_internal(text, value, base); } bool safe_strtou128_base(absl::string_view text, uint128* value, int base) { return safe_uint_internal(text, value, base); } } // namespace numbers_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/cord_test_helpers.h0000644000175000017510000000754714737212474023730 0ustar nileshnilesh// // Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef ABSL_STRINGS_CORD_TEST_HELPERS_H_ #define ABSL_STRINGS_CORD_TEST_HELPERS_H_ #include #include #include #include "absl/base/config.h" #include "absl/strings/cord.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN // Cord sizes relevant for testing enum class TestCordSize { // An empty value kEmpty = 0, // An inlined string value kInlined = cord_internal::kMaxInline / 2 + 1, // 'Well known' SSO lengths (excluding terminating zero). // libstdcxx has a maximum SSO of 15, libc++ has a maximum SSO of 22. kStringSso1 = 15, kStringSso2 = 22, // A string value which is too large to fit in inlined data, but small enough // such that Cord prefers copying the value if possible, i.e.: not stealing // std::string inputs, or referencing existing CordReps on Append, etc. kSmall = cord_internal::kMaxBytesToCopy / 2 + 1, // A string value large enough that Cord prefers to reference or steal from // existing inputs rather than copying contents of the input. kMedium = cord_internal::kMaxFlatLength / 2 + 1, // A string value large enough to cause it to be stored in multiple flats. kLarge = cord_internal::kMaxFlatLength * 4 }; // To string helper inline absl::string_view ToString(TestCordSize size) { switch (size) { case TestCordSize::kEmpty: return "Empty"; case TestCordSize::kInlined: return "Inlined"; case TestCordSize::kSmall: return "Small"; case TestCordSize::kStringSso1: return "StringSso1"; case TestCordSize::kStringSso2: return "StringSso2"; case TestCordSize::kMedium: return "Medium"; case TestCordSize::kLarge: return "Large"; } return "???"; } // Returns the length matching the specified size inline size_t Length(TestCordSize size) { return static_cast(size); } // Stream output helper inline std::ostream& operator<<(std::ostream& stream, TestCordSize size) { return stream << ToString(size); } // Creates a multi-segment Cord from an iterable container of strings. The // resulting Cord is guaranteed to have one segment for every string in the // container. This allows code to be unit tested with multi-segment Cord // inputs. // // Example: // // absl::Cord c = absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"}); // EXPECT_FALSE(c.GetFlat(&unused)); // // The mechanism by which this Cord is created is an implementation detail. Any // implementation that produces a multi-segment Cord may produce a flat Cord in // the future as new optimizations are added to the Cord class. // MakeFragmentedCord will, however, always be updated to return a multi-segment // Cord. template Cord MakeFragmentedCord(const Container& c) { Cord result; for (const auto& s : c) { auto* external = new std::string(s); Cord tmp = absl::MakeCordFromExternal( *external, [external](absl::string_view) { delete external; }); tmp.Prepend(result); result = tmp; } return result; } inline Cord MakeFragmentedCord(std::initializer_list list) { return MakeFragmentedCord>(list); } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CORD_TEST_HELPERS_H_ s2/tools/vendor/abseil-cpp/absl/strings/ascii.cc0000644000175000017510000002533414737212474021440 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/ascii.h" #include #include #include namespace absl { ABSL_NAMESPACE_BEGIN namespace ascii_internal { // # Table generated by this Python code (bit 0x02 is currently unused): // TODO(mbar) Move Python code for generation of table to BUILD and link here. // NOTE: The kAsciiPropertyBits table used within this code was generated by // Python code of the following form. (Bit 0x02 is currently unused and // available.) // // def Hex2(n): // return '0x' + hex(n/16)[2:] + hex(n%16)[2:] // def IsPunct(ch): // return (ord(ch) >= 32 and ord(ch) < 127 and // not ch.isspace() and not ch.isalnum()) // def IsBlank(ch): // return ch in ' \t' // def IsCntrl(ch): // return ord(ch) < 32 or ord(ch) == 127 // def IsXDigit(ch): // return ch.isdigit() or ch.lower() in 'abcdef' // for i in range(128): // ch = chr(i) // mask = ((ch.isalpha() and 0x01 or 0) | // (ch.isalnum() and 0x04 or 0) | // (ch.isspace() and 0x08 or 0) | // (IsPunct(ch) and 0x10 or 0) | // (IsBlank(ch) and 0x20 or 0) | // (IsCntrl(ch) and 0x40 or 0) | // (IsXDigit(ch) and 0x80 or 0)) // print Hex2(mask) + ',', // if i % 16 == 7: // print ' //', Hex2(i & 0x78) // elif i % 16 == 15: // print // clang-format off // Array of bitfields holding character information. Each bit value corresponds // to a particular character feature. For readability, and because the value // of these bits is tightly coupled to this implementation, the individual bits // are not named. Note that bitfields for all characters above ASCII 127 are // zero-initialized. ABSL_DLL const unsigned char kPropertyBits[256] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, // 0x30 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, }; // Array of characters for the ascii_tolower() function. For values 'A' // through 'Z', return the lower-case character; otherwise, return the // identity of the passed character. ABSL_DLL const char kToLower[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', '\x40', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', }; // Array of characters for the ascii_toupper() function. For values 'a' // through 'z', return the upper-case character; otherwise, return the // identity of the passed character. ABSL_DLL const char kToUpper[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', '\x60', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', }; // clang-format on template constexpr void AsciiStrCaseFold(char* p, char* end) { // The upper- and lowercase versions of ASCII characters differ by only 1 bit. // When we need to flip the case, we can xor with this bit to achieve the // desired result. Note that the choice of 'a' and 'A' here is arbitrary. We // could have chosen 'z' and 'Z', or any other pair of characters as they all // have the same single bit difference. constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A'; constexpr char ch_a = ToUpper ? 'a' : 'A'; constexpr char ch_z = ToUpper ? 'z' : 'Z'; for (; p < end; ++p) { unsigned char v = static_cast(*p); // We use & instead of && to ensure this always stays branchless // We use static_cast to suppress -Wbitwise-instead-of-logical bool is_in_range = static_cast(static_cast(ch_a <= v) & static_cast(v <= ch_z)); v ^= is_in_range ? kAsciiCaseBitFlip : 0; *p = static_cast(v); } } static constexpr size_t ValidateAsciiCasefold() { constexpr size_t num_chars = 1 + CHAR_MAX - CHAR_MIN; size_t incorrect_index = 0; char lowered[num_chars] = {}; char uppered[num_chars] = {}; for (unsigned int i = 0; i < num_chars; ++i) { uppered[i] = lowered[i] = static_cast(i); } AsciiStrCaseFold(&lowered[0], &lowered[num_chars]); AsciiStrCaseFold(&uppered[0], &uppered[num_chars]); for (size_t i = 0; i < num_chars; ++i) { const char ch = static_cast(i), ch_upper = ('a' <= ch && ch <= 'z' ? 'A' + (ch - 'a') : ch), ch_lower = ('A' <= ch && ch <= 'Z' ? 'a' + (ch - 'A') : ch); if (uppered[i] != ch_upper || lowered[i] != ch_lower) { incorrect_index = i > 0 ? i : num_chars; break; } } return incorrect_index; } static_assert(ValidateAsciiCasefold() == 0, "error in case conversion"); } // namespace ascii_internal void AsciiStrToLower(std::string* s) { char* p = &(*s)[0]; // Guaranteed to be valid for empty strings return ascii_internal::AsciiStrCaseFold(p, p + s->size()); } void AsciiStrToUpper(std::string* s) { char* p = &(*s)[0]; // Guaranteed to be valid for empty strings return ascii_internal::AsciiStrCaseFold(p, p + s->size()); } void RemoveExtraAsciiWhitespace(std::string* str) { auto stripped = StripAsciiWhitespace(*str); if (stripped.empty()) { str->clear(); return; } auto input_it = stripped.begin(); auto input_end = stripped.end(); auto output_it = &(*str)[0]; bool is_ws = false; for (; input_it < input_end; ++input_it) { if (is_ws) { // Consecutive whitespace? Keep only the last. is_ws = absl::ascii_isspace(static_cast(*input_it)); if (is_ws) --output_it; } else { is_ws = absl::ascii_isspace(static_cast(*input_it)); } *output_it = *input_it; ++output_it; } str->erase(static_cast(output_it - &(*str)[0])); } ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/internal/0000755000175000017510000000000014737212474021646 5ustar nileshnileshs2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_info.h0000644000175000017510000003051414737212474024156 0ustar nileshnilesh// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ #include #include #include #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/spinlock.h" #include "absl/base/thread_annotations.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_functions.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/synchronization/mutex.h" #include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // CordzInfo tracks a profiled Cord. Each of these objects can be in two places. // If a Cord is alive, the CordzInfo will be in the global_cordz_infos map, and // can also be retrieved via the linked list starting with // global_cordz_infos_head and continued via the cordz_info_next() method. When // a Cord has reached the end of its lifespan, the CordzInfo object will be // migrated out of the global_cordz_infos list and the global_cordz_infos_map, // and will either be deleted or appended to the global_delete_queue. If it is // placed on the global_delete_queue, the CordzInfo object will be cleaned in // the destructor of a CordzSampleToken object. class ABSL_LOCKABLE CordzInfo : public CordzHandle { public: using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; // TrackCord creates a CordzInfo instance which tracks important metrics of // a sampled cord, and stores the created CordzInfo instance into `cord'. All // CordzInfo instances are placed in a global list which is used to discover // and snapshot all actively tracked cords. Callers are responsible for // calling UntrackCord() before the tracked Cord instance is deleted, or to // stop tracking the sampled Cord. Callers are also responsible for guarding // changes to the 'tree' value of a Cord (InlineData.tree) through the Lock() // and Unlock() calls. Any change resulting in a new tree value for the cord // requires a call to SetCordRep() before the old tree has been unreffed // and/or deleted. `method` identifies the Cord public API method initiating // the cord to be sampled. // Requires `cord` to hold a tree, and `cord.cordz_info()` to be null. static void TrackCord(InlineData& cord, MethodIdentifier method); // Identical to TrackCord(), except that this function fills the // `parent_stack` and `parent_method` properties of the returned CordzInfo // instance from the provided `src` instance if `src` is sampled. // This function should be used for sampling 'copy constructed' and 'copy // assigned' cords. This function allows 'cord` to be already sampled, in // which case the CordzInfo will be newly created from `src`. static void TrackCord(InlineData& cord, const InlineData& src, MethodIdentifier method); // Maybe sample the cord identified by 'cord' for method 'method'. // Uses `cordz_should_profile` to randomly pick cords to be sampled, and if // so, invokes `TrackCord` to start sampling `cord`. static void MaybeTrackCord(InlineData& cord, MethodIdentifier method); // Maybe sample the cord identified by 'cord' for method 'method'. // `src` identifies a 'parent' cord which is assigned to `cord`, typically the // input cord for a copy constructor, or an assign method such as `operator=` // `cord` will be sampled if (and only if) `src` is sampled. // If `cord` is currently being sampled and `src` is not being sampled, then // this function will stop sampling the cord and reset the cord's cordz_info. // // Previously this function defined that `cord` will be sampled if either // `src` is sampled, or if `cord` is randomly picked for sampling. However, // this can cause issues, as there may be paths where some cord is assigned an // indirect copy of it's own value. As such a 'string of copies' would then // remain sampled (`src.is_profiled`), then assigning such a cord back to // 'itself' creates a cycle where the cord will converge to 'always sampled`. // // For example: // // Cord x; // for (...) { // // Copy ctor --> y.is_profiled := x.is_profiled | random(...) // Cord y = x; // ... // // Assign x = y --> x.is_profiled = y.is_profiled | random(...) // // ==> x.is_profiled |= random(...) // // ==> x converges to 'always profiled' // x = y; // } static void MaybeTrackCord(InlineData& cord, const InlineData& src, MethodIdentifier method); // Stops tracking changes for a sampled cord, and deletes the provided info. // This function must be called before the sampled cord instance is deleted, // and before the root cordrep of the sampled cord is unreffed. // This function may extend the lifetime of the cordrep in cases where the // CordInfo instance is being held by a concurrent collection thread. void Untrack(); // Invokes UntrackCord() on `info` if `info` is not null. static void MaybeUntrackCord(CordzInfo* info); CordzInfo() = delete; CordzInfo(const CordzInfo&) = delete; CordzInfo& operator=(const CordzInfo&) = delete; // Retrieves the oldest existing CordzInfo. static CordzInfo* Head(const CordzSnapshot& snapshot) ABSL_NO_THREAD_SAFETY_ANALYSIS; // Retrieves the next oldest existing CordzInfo older than 'this' instance. CordzInfo* Next(const CordzSnapshot& snapshot) const ABSL_NO_THREAD_SAFETY_ANALYSIS; // Locks this instance for the update identified by `method`. // Increases the count for `method` in `update_tracker`. void Lock(MethodIdentifier method) ABSL_EXCLUSIVE_LOCK_FUNCTION(mutex_); // Unlocks this instance. If the contained `rep` has been set to null // indicating the Cord has been cleared or is otherwise no longer sampled, // then this method will delete this CordzInfo instance. void Unlock() ABSL_UNLOCK_FUNCTION(mutex_); // Asserts that this CordzInfo instance is locked. void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_); // Updates the `rep` property of this instance. This methods is invoked by // Cord logic each time the root node of a sampled Cord changes, and before // the old root reference count is deleted. This guarantees that collection // code can always safely take a reference on the tracked cord. // Requires a lock to be held through the `Lock()` method. // TODO(b/117940323): annotate with ABSL_EXCLUSIVE_LOCKS_REQUIRED once all // Cord code is in a state where this can be proven true by the compiler. void SetCordRep(CordRep* rep); // Returns the current `rep` property of this instance with a reference // added, or null if this instance represents a cord that has since been // deleted or untracked. CordRep* RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_); // Returns the current value of `rep_` for testing purposes only. CordRep* GetCordRepForTesting() const ABSL_NO_THREAD_SAFETY_ANALYSIS { return rep_; } // Sets the current value of `rep_` for testing purposes only. void SetCordRepForTesting(CordRep* rep) ABSL_NO_THREAD_SAFETY_ANALYSIS { rep_ = rep; } // Returns the stack trace for where the cord was first sampled. Cords are // potentially sampled when they promote from an inlined cord to a tree or // ring representation, which is not necessarily the location where the cord // was first created. Some cords are created as inlined cords, and only as // data is added do they become a non-inlined cord. However, typically the // location represents reasonably well where the cord is 'created'. absl::Span GetStack() const; // Returns the stack trace for a sampled cord's 'parent stack trace'. This // value may be set if the cord is sampled (promoted) after being created // from, or being assigned the value of an existing (sampled) cord. absl::Span GetParentStack() const; // Retrieves the CordzStatistics associated with this Cord. The statistics // are only updated when a Cord goes through a mutation, such as an Append // or RemovePrefix. CordzStatistics GetCordzStatistics() const; private: using SpinLock = absl::base_internal::SpinLock; using SpinLockHolder = ::absl::base_internal::SpinLockHolder; // Global cordz info list. CordzInfo stores a pointer to the global list // instance to harden against ODR violations. struct List { constexpr explicit List(absl::ConstInitType) : mutex(absl::kConstInit, absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) {} SpinLock mutex; std::atomic head ABSL_GUARDED_BY(mutex){nullptr}; }; static constexpr size_t kMaxStackDepth = 64; explicit CordzInfo(CordRep* rep, const CordzInfo* src, MethodIdentifier method); ~CordzInfo() override; // Sets `rep_` without holding a lock. void UnsafeSetCordRep(CordRep* rep) ABSL_NO_THREAD_SAFETY_ANALYSIS; void Track(); // Returns the parent method from `src`, which is either `parent_method_` or // `method_` depending on `parent_method_` being kUnknown. // Returns kUnknown if `src` is null. static MethodIdentifier GetParentMethod(const CordzInfo* src); // Fills the provided stack from `src`, copying either `parent_stack_` or // `stack_` depending on `parent_stack_` being empty, returning the size of // the parent stack. // Returns 0 if `src` is null. static size_t FillParentStack(const CordzInfo* src, void** stack); void ODRCheck() const { #ifndef NDEBUG ABSL_RAW_CHECK(list_ == &global_list_, "ODR violation in Cord"); #endif } // Non-inlined implementation of `MaybeTrackCord`, which is executed if // either `src` is sampled or `cord` is sampled, and either untracks or // tracks `cord` as documented per `MaybeTrackCord`. static void MaybeTrackCordImpl(InlineData& cord, const InlineData& src, MethodIdentifier method); ABSL_CONST_INIT static List global_list_; List* const list_ = &global_list_; // ci_prev_ and ci_next_ require the global list mutex to be held. // Unfortunately we can't use thread annotations such that the thread safety // analysis understands that list_ and global_list_ are one and the same. std::atomic ci_prev_{nullptr}; std::atomic ci_next_{nullptr}; mutable absl::Mutex mutex_; CordRep* rep_ ABSL_GUARDED_BY(mutex_); void* stack_[kMaxStackDepth]; void* parent_stack_[kMaxStackDepth]; const size_t stack_depth_; const size_t parent_stack_depth_; const MethodIdentifier method_; const MethodIdentifier parent_method_; CordzUpdateTracker update_tracker_; const absl::Time create_time_; }; inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( InlineData& cord, MethodIdentifier method) { if (ABSL_PREDICT_FALSE(cordz_should_profile())) { TrackCord(cord, method); } } inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord( InlineData& cord, const InlineData& src, MethodIdentifier method) { if (ABSL_PREDICT_FALSE(InlineData::is_either_profiled(cord, src))) { MaybeTrackCordImpl(cord, src, method); } } inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeUntrackCord( CordzInfo* info) { if (ABSL_PREDICT_FALSE(info)) { info->Untrack(); } } inline void CordzInfo::AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK(mutex_) { #ifndef NDEBUG mutex_.AssertHeld(); #endif } inline void CordzInfo::SetCordRep(CordRep* rep) { AssertHeld(); rep_ = rep; } inline void CordzInfo::UnsafeSetCordRep(CordRep* rep) { rep_ = rep; } inline CordRep* CordzInfo::RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_) { MutexLock lock(&mutex_); return rep_ ? CordRep::Ref(rep_) : nullptr; } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_INFO_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_handle.h0000644000175000017510000000775714737212474024473 0ustar nileshnilesh// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ #include #include #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // This base class allows multiple types of object (CordzInfo and // CordzSampleToken) to exist simultaneously on the delete queue (pointed to by // global_dq_tail and traversed using dq_prev_ and dq_next_). The // delete queue guarantees that once a profiler creates a CordzSampleToken and // has gained visibility into a CordzInfo object, that CordzInfo object will not // be deleted prematurely. This allows the profiler to inspect all CordzInfo // objects that are alive without needing to hold a global lock. class ABSL_DLL CordzHandle { public: CordzHandle() : CordzHandle(false) {} bool is_snapshot() const { return is_snapshot_; } // Returns true if this instance is safe to be deleted because it is either a // snapshot, which is always safe to delete, or not included in the global // delete queue and thus not included in any snapshot. // Callers are responsible for making sure this instance can not be newly // discovered by other threads. For example, CordzInfo instances first de-list // themselves from the global CordzInfo list before determining if they are // safe to be deleted directly. // If SafeToDelete returns false, callers MUST use the Delete() method to // safely queue CordzHandle instances for deletion. bool SafeToDelete() const; // Deletes the provided instance, or puts it on the delete queue to be deleted // once there are no more sample tokens (snapshot) instances potentially // referencing the instance. `handle` should not be null. static void Delete(CordzHandle* handle); // Returns the current entries in the delete queue in LIFO order. static std::vector DiagnosticsGetDeleteQueue(); // Returns true if the provided handle is nullptr or guarded by this handle. // Since the CordzSnapshot token is itself a CordzHandle, this method will // allow tests to check if that token is keeping an arbitrary CordzHandle // alive. bool DiagnosticsHandleIsSafeToInspect(const CordzHandle* handle) const; // Returns the current entries in the delete queue, in LIFO order, that are // protected by this. CordzHandle objects are only placed on the delete queue // after CordzHandle::Delete is called with them as an argument. Only // CordzHandle objects that are not also CordzSnapshot objects will be // included in the return vector. For each of the handles in the return // vector, the earliest that their memory can be freed is when this // CordzSnapshot object is deleted. std::vector DiagnosticsGetSafeToInspectDeletedHandles(); protected: explicit CordzHandle(bool is_snapshot); virtual ~CordzHandle(); private: const bool is_snapshot_; // dq_prev_ and dq_next_ require the global queue mutex to be held. // Unfortunately we can't use thread annotations such that the thread safety // analysis understands that queue_ and global_queue_ are one and the same. CordzHandle* dq_prev_ = nullptr; CordzHandle* dq_next_ = nullptr; }; class CordzSnapshot : public CordzHandle { public: CordzSnapshot() : CordzHandle(true) {} }; } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_HANDLE_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cord_rep_btree.h0000644000175000017510000012046414737212474025004 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_ #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_ #include #include #include #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // `SetCordBtreeExhaustiveValidation()` can be set to force exhaustive // validation in debug assertions, and code that calls `IsValid()` // explicitly. By default, assertions should be relatively cheap and // AssertValid() can easily lead to O(n^2) complexity as recursive / full tree // validation is O(n). void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation); bool IsCordBtreeExhaustiveValidationEnabled(); class CordRepBtreeNavigator; // CordRepBtree is as the name implies a btree implementation of a Cordrep tree. // Data is stored at the leaf level only, non leaf nodes contain down pointers // only. Allowed types of data edges are FLAT, EXTERNAL and SUBSTRINGs of FLAT // or EXTERNAL nodes. The implementation allows for data to be added to either // end of the tree only, it does not provide any 'insert' logic. This has the // benefit that we can expect good fill ratios: all nodes except the outer // 'legs' will have 100% fill ratios for trees built using Append/Prepend // methods. Merged trees will typically have a fill ratio well above 50% as in a // similar fashion, one side of the merged tree will typically have a 100% fill // ratio, and the 'open' end will average 50%. All operations are O(log(n)) or // better, and the tree never needs balancing. // // All methods accepting a CordRep* or CordRepBtree* adopt a reference on that // input unless explicitly stated otherwise. All functions returning a CordRep* // or CordRepBtree* instance transfer a reference back to the caller. // Simplified, callers both 'donate' and 'consume' a reference count on each // call, simplifying the API. An example of building a tree: // // CordRepBtree* tree = CordRepBtree::Create(MakeFlat("Hello")); // tree = CordRepBtree::Append(tree, MakeFlat("world")); // // In the above example, all inputs are consumed, making each call affecting // `tree` reference count neutral. The returned `tree` value can be different // from the input if the input is shared with other threads, or if the tree // grows in height, but callers typically never have to concern themselves with // that and trust that all methods DTRT at all times. class CordRepBtree : public CordRep { public: // EdgeType identifies `front` and `back` enum values. // Various implementations in CordRepBtree such as `Add` and `Edge` are // generic and templated on operating on either of the boundary edges. // For more information on the possible edges contained in a CordRepBtree // instance see the documentation for `edges_`. enum class EdgeType { kFront, kBack }; // Convenience constants into `EdgeType` static constexpr EdgeType kFront = EdgeType::kFront; static constexpr EdgeType kBack = EdgeType::kBack; // Maximum number of edges: based on experiments and performance data, we can // pick suitable values resulting in optimum cacheline aligned values. The // preferred values are based on 64-bit systems where we aim to align this // class onto 64 bytes, i.e.: 6 = 64 bytes, 14 = 128 bytes, etc. // TODO(b/192061034): experiment with alternative sizes. static constexpr size_t kMaxCapacity = 6; // Reasonable maximum height of the btree. We can expect a fill ratio of at // least 50%: trees are always expanded at the front or back. Concatenating // trees will then typically fold at the top most node, where the lower nodes // are at least at capacity on one side of joined inputs. At a lower fill // rate of 4 edges per node, we have capacity for ~16 million leaf nodes. // We will fail / abort if an application ever exceeds this height, which // should be extremely rare (near impossible) and be an indication of an // application error: we do not assume it reasonable for any application to // operate correctly with such monster trees. // Another compelling reason for the number `12` is that any contextual stack // required for navigation or insertion requires 12 words and 12 bytes, which // fits inside 2 cache lines with some room to spare, and is reasonable as a // local stack variable compared to Cord's current near 400 bytes stack use. // The maximum `height` value of a node is then `kMaxDepth - 1` as node height // values start with a value of 0 for leaf nodes. static constexpr size_t kMaxDepth = 12; // See comments on height() for why this is an int and not a size_t. static constexpr int kMaxHeight = static_cast(kMaxDepth - 1); // `Action` defines the action for unwinding changes done at the btree's leaf // level that need to be propagated up to the parent node(s). Each operation // on a node has an effect / action defined as follows: // - kSelf // The operation (add / update, etc) was performed directly on the node as // the node is private to the current thread (i.e.: not shared directly or // indirectly through a refcount > 1). Changes can be propagated directly to // all parent nodes as all parent nodes are also then private to the current // thread. // - kCopied // The operation (add / update, etc) was performed on a copy of the original // node, as the node is (potentially) directly or indirectly shared with // other threads. Changes need to be propagated into the parent nodes where // the old down pointer must be unreffed and replaced with this new copy. // Such changes to parent nodes may themselves require a copy if the parent // node is also shared. A kCopied action can propagate all the way to the // top node where we then must unref the `tree` input provided by the // caller, and return the new copy. // - kPopped // The operation (typically add) could not be satisfied due to insufficient // capacity in the targeted node, and a new 'leg' was created that needs to // be added into the parent node. For example, adding a FLAT inside a leaf // node that is at capacity will create a new leaf node containing that // FLAT, that needs to be 'popped' up the btree. Such 'pop' actions can // cascade up the tree if parent nodes are also at capacity. A 'Popped' // action propagating all the way to the top of the tree will result in // the tree becoming one level higher than the current tree through a final // `CordRepBtree::New(tree, popped)` call, resulting in a new top node // referencing the old tree and the new (fully popped upwards) 'leg'. enum Action { kSelf, kCopied, kPopped }; // Result of an operation on a node. See the `Action` enum for details. struct OpResult { CordRepBtree* tree; Action action; }; // Return value of the CopyPrefix and CopySuffix methods which can // return a node or data edge at any height inside the tree. // A height of 0 defines the lowest (leaf) node, a height of -1 identifies // `edge` as being a plain data node: EXTERNAL / FLAT or SUBSTRING thereof. struct CopyResult { CordRep* edge; int height; }; // Logical position inside a node: // - index: index of the edge. // - n: size or offset value depending on context. struct Position { size_t index; size_t n; }; // Creates a btree from the given input. Adopts a ref of `rep`. // If the input `rep` is itself a btree, i.e., `IsBtree()`, then this // function immediately returns `rep->btree()`. If the input is a valid data // edge (see IsDataEdge()), then a new leaf node is returned containing `rep` // as the sole data edge. Else, the input is assumed to be a (legacy) concat // tree, and the input is consumed and transformed into a btree(). static CordRepBtree* Create(CordRep* rep); // Destroys the provided tree. Should only be called by cord internal API's, // typically after a ref_count.Decrement() on the last reference count. static void Destroy(CordRepBtree* tree); // Destruction static void Delete(CordRepBtree* tree) { delete tree; } // Use CordRep::Unref() as we overload for absl::Span. using CordRep::Unref; // Unrefs all edges in `edges` which are assumed to be 'likely one'. static void Unref(absl::Span edges); // Appends / Prepends an existing CordRep instance to this tree. // The below methods accept three types of input: // 1) `rep` is a data node (See `IsDataNode` for valid data edges). // `rep` is appended or prepended to this tree 'as is'. // 2) `rep` is a BTREE. // `rep` is merged into `tree` respecting the Append/Prepend order. // 3) `rep` is some other (legacy) type. // `rep` is converted in place and added to `tree` // Requires `tree` and `rep` to be not null. static CordRepBtree* Append(CordRepBtree* tree, CordRep* rep); static CordRepBtree* Prepend(CordRepBtree* tree, CordRep* rep); // Append/Prepend the data in `data` to this tree. // The `extra` parameter defines how much extra capacity should be allocated // for any additional FLAT being allocated. This is an optimization hint from // the caller. For example, a caller may need to add 2 string_views of data // "abc" and "defghi" which are not consecutive. The caller can in this case // invoke `AddData(tree, "abc", 6)`, and any newly added flat is allocated // where possible with at least 6 bytes of extra capacity beyond `length`. // This helps avoiding data getting fragmented over multiple flats. // There is no limit on the size of `data`. If `data` can not be stored inside // a single flat, then the function will iteratively add flats until all data // has been consumed and appended or prepended to the tree. static CordRepBtree* Append(CordRepBtree* tree, string_view data, size_t extra = 0); static CordRepBtree* Prepend(CordRepBtree* tree, string_view data, size_t extra = 0); // Returns a new tree, containing `n` bytes of data from this instance // starting at offset `offset`. Where possible, the returned tree shares // (re-uses) data edges and nodes with this instance to minimize the // combined memory footprint of both trees. // Requires `offset + n <= length`. Returns `nullptr` if `n` is zero. CordRep* SubTree(size_t offset, size_t n); // Removes `n` trailing bytes from `tree`, and returns the resulting tree // or data edge. Returns `tree` if n is zero, and nullptr if n == length. // This function is logically identical to: // result = tree->SubTree(0, tree->length - n); // Unref(tree); // return result; // However, the actual implementation will as much as possible perform 'in // place' modifications on the tree on all nodes and edges that are mutable. // For example, in a fully privately owned tree with the last edge being a // flat of length 12, RemoveSuffix(1) will simply set the length of that data // edge to 11, and reduce the length of all nodes on the edge path by 1. static CordRep* RemoveSuffix(CordRepBtree* tree, size_t n); // Returns the character at the given offset. char GetCharacter(size_t offset) const; // Returns true if this node holds a single data edge, and if so, sets // `fragment` to reference the contained data. `fragment` is an optional // output parameter and allowed to be null. bool IsFlat(absl::string_view* fragment) const; // Returns true if the data of `n` bytes starting at offset `offset` // is contained in a single data edge, and if so, sets fragment to reference // the contained data. `fragment` is an optional output parameter and allowed // to be null. bool IsFlat(size_t offset, size_t n, absl::string_view* fragment) const; // Returns a span (mutable range of bytes) of up to `size` bytes into the // last FLAT data edge inside this tree under the following conditions: // - none of the nodes down into the FLAT node are shared. // - the last data edge in this tree is a non-shared FLAT. // - the referenced FLAT has additional capacity available. // If all these conditions are met, a non-empty span is returned, and the // length of the flat node and involved tree nodes have been increased by // `span.length()`. The caller is responsible for immediately assigning values // to all uninitialized data reference by the returned span. // Requires `this->refcount.IsOne()`: this function forces the caller to do // this fast path check on the top level node, as this is the most commonly // shared node of a cord tree. Span GetAppendBuffer(size_t size); // Extracts the right-most data edge from this tree iff: // - the tree and all internal edges to the right-most node are not shared. // - the right-most node is a FLAT node and not shared. // - the right-most node has at least the desired extra capacity. // // Returns {tree, nullptr} if any of the above conditions are not met. // This method effectively removes data from the tree. The intent of this // method is to allow applications appending small string data to use // pre-existing capacity, and add the modified rep back to the tree. // // Simplified such code would look similar to this: // void MyTreeBuilder::Append(string_view data) { // ExtractResult result = CordRepBtree::ExtractAppendBuffer(tree_, 1); // if (CordRep* rep = result.extracted) { // size_t available = rep->Capacity() - rep->length; // size_t n = std::min(data.size(), n); // memcpy(rep->Data(), data.data(), n); // rep->length += n; // data.remove_prefix(n); // if (!result.tree->IsBtree()) { // tree_ = CordRepBtree::Create(result.tree); // } // tree_ = CordRepBtree::Append(tree_, rep); // } // ... // // Remaining edge in `result.tree`. // } static ExtractResult ExtractAppendBuffer(CordRepBtree* tree, size_t extra_capacity = 1); // Returns the `height` of the tree. The height of a tree is limited to // kMaxHeight. `height` is implemented as an `int` as in some places we // use negative (-1) values for 'data edges'. int height() const { return static_cast(storage[0]); } // Properties: begin, back, end, front/back boundary indexes. size_t begin() const { return static_cast(storage[1]); } size_t back() const { return static_cast(storage[2]) - 1; } size_t end() const { return static_cast(storage[2]); } size_t index(EdgeType edge) const { return edge == kFront ? begin() : back(); } // Properties: size and capacity. // `capacity` contains the current capacity of this instance, where // `kMaxCapacity` contains the maximum capacity of a btree node. // For now, `capacity` and `kMaxCapacity` return the same value, but this may // change in the future if we see benefit in dynamically sizing 'small' nodes // to 'large' nodes for large data trees. size_t size() const { return end() - begin(); } size_t capacity() const { return kMaxCapacity; } // Edge access inline CordRep* Edge(size_t index) const; inline CordRep* Edge(EdgeType edge_type) const; inline absl::Span Edges() const; inline absl::Span Edges(size_t begin, size_t end) const; // Returns reference to the data edge at `index`. // Requires this instance to be a leaf node, and `index` to be valid index. inline absl::string_view Data(size_t index) const; // Diagnostics: returns true if `tree` is valid and internally consistent. // If `shallow` is false, then the provided top level node and all child nodes // below it are recursively checked. If `shallow` is true, only the provided // node in `tree` and the cumulative length, type and height of the direct // child nodes of `tree` are checked. The value of `shallow` is ignored if the // internal `cord_btree_exhaustive_validation` diagnostics variable is true, // in which case the performed validations works as if `shallow` were false. // This function is intended for debugging and testing purposes only. static bool IsValid(const CordRepBtree* tree, bool shallow = false); // Diagnostics: asserts that the provided tree is valid. // `AssertValid()` performs a shallow validation by default. `shallow` can be // set to false in which case an exhaustive validation is performed. This // function is implemented in terms of calling `IsValid()` and asserting the // return value to be true. See `IsValid()` for more information. // This function is intended for debugging and testing purposes only. static CordRepBtree* AssertValid(CordRepBtree* tree, bool shallow = true); static const CordRepBtree* AssertValid(const CordRepBtree* tree, bool shallow = true); // Diagnostics: dump the contents of this tree to `stream`. // This function is intended for debugging and testing purposes only. static void Dump(const CordRep* rep, std::ostream& stream); static void Dump(const CordRep* rep, absl::string_view label, std::ostream& stream); static void Dump(const CordRep* rep, absl::string_view label, bool include_contents, std::ostream& stream); // Adds the edge `edge` to this node if possible. `owned` indicates if the // current node is potentially shared or not with other threads. Returns: // - {kSelf, } // The edge was directly added to this node. // - {kCopied, } // The edge was added to a copy of this node. // - {kPopped, New(edge, height())} // A new leg with the edge was created as this node has no extra capacity. template inline OpResult AddEdge(bool owned, CordRep* edge, size_t delta); // Replaces the front or back edge with the provided new edge. Returns: // - {kSelf, } // The edge was directly set in this node. The old edge is unreffed. // - {kCopied, } // A copy of this node was created with the new edge value. // In both cases, the function adopts a reference on `edge`. template OpResult SetEdge(bool owned, CordRep* edge, size_t delta); // Creates a new empty node at the specified height. static CordRepBtree* New(int height = 0); // Creates a new node containing `rep`, with the height being computed // automatically based on the type of `rep`. static CordRepBtree* New(CordRep* rep); // Creates a new node containing both `front` and `back` at height // `front.height() + 1`. Requires `back.height() == front.height()`. static CordRepBtree* New(CordRepBtree* front, CordRepBtree* back); // Creates a fully balanced tree from the provided tree by rebuilding a new // tree from all data edges in the input. This function is automatically // invoked internally when the tree exceeds the maximum height. static CordRepBtree* Rebuild(CordRepBtree* tree); private: CordRepBtree() = default; ~CordRepBtree() = default; // Initializes the main properties `tag`, `begin`, `end`, `height`. inline void InitInstance(int height, size_t begin = 0, size_t end = 0); // Direct property access begin / end void set_begin(size_t begin) { storage[1] = static_cast(begin); } void set_end(size_t end) { storage[2] = static_cast(end); } // Decreases the value of `begin` by `n`, and returns the new value. Notice // how this returns the new value unlike atomic::fetch_add which returns the // old value. This is because this is used to prepend edges at 'begin - 1'. size_t sub_fetch_begin(size_t n) { storage[1] -= static_cast(n); return storage[1]; } // Increases the value of `end` by `n`, and returns the previous value. This // function is typically used to append edges at 'end'. size_t fetch_add_end(size_t n) { const uint8_t current = storage[2]; storage[2] = static_cast(current + n); return current; } // Returns the index of the last edge starting on, or before `offset`, with // `n` containing the relative offset of `offset` inside that edge. // Requires `offset` < length. Position IndexOf(size_t offset) const; // Returns the index of the last edge starting before `offset`, with `n` // containing the relative offset of `offset` inside that edge. // This function is useful to find the edges for some span of bytes ending at // `offset` (i.e., `n` bytes). For example: // // Position pos = IndexBefore(n) // edges = Edges(begin(), pos.index) // All full edges (may be empty) // last = Sub(Edge(pos.index), 0, pos.n) // Last partial edge (may be empty) // // Requires 0 < `offset` <= length. Position IndexBefore(size_t offset) const; // Returns the index of the edge ending at (or on) length `length`, and the // number of bytes inside that edge up to `length`. For example, if we have a // Node with 2 edges, one of 10 and one of 20 long, then IndexOfLength(27) // will return {1, 17}, and IndexOfLength(10) will return {0, 10}. Position IndexOfLength(size_t n) const; // Identical to the above function except starting from the position `front`. // This function is equivalent to `IndexBefore(front.n + offset)`, with // the difference that this function is optimized to start at `front.index`. Position IndexBefore(Position front, size_t offset) const; // Returns the index of the edge directly beyond the edge containing offset // `offset`, with `n` containing the distance of that edge from `offset`. // This function is useful for iteratively finding suffix nodes and remaining // partial bytes in left-most suffix nodes as for example in CopySuffix. // Requires `offset` < length. Position IndexBeyond(size_t offset) const; // Creates a new leaf node containing as much data as possible from `data`. // The data is added either forwards or reversed depending on `edge_type`. // Callers must check the length of the returned node to determine if all data // was copied or not. // See the `Append/Prepend` function for the meaning and purpose of `extra`. template static CordRepBtree* NewLeaf(absl::string_view data, size_t extra); // Creates a raw copy of this Btree node with the specified length, copying // all properties, but without adding any references to existing edges. CordRepBtree* CopyRaw(size_t new_length) const; // Creates a full copy of this Btree node, adding a reference on all edges. CordRepBtree* Copy() const; // Creates a partial copy of this Btree node, copying all edges up to `end`, // adding a reference on each copied edge, and sets the length of the newly // created copy to `new_length`. CordRepBtree* CopyBeginTo(size_t end, size_t new_length) const; // Returns a tree containing the edges [tree->begin(), end) and length // of `new_length`. This method consumes a reference on the provided // tree, and logically performs the following operation: // result = tree->CopyBeginTo(end, new_length); // CordRep::Unref(tree); // return result; static CordRepBtree* ConsumeBeginTo(CordRepBtree* tree, size_t end, size_t new_length); // Creates a partial copy of this Btree node, copying all edges starting at // `begin`, adding a reference on each copied edge, and sets the length of // the newly created copy to `new_length`. CordRepBtree* CopyToEndFrom(size_t begin, size_t new_length) const; // Extracts and returns the front edge from the provided tree. // This method consumes a reference on the provided tree, and logically // performs the following operation: // edge = CordRep::Ref(tree->Edge(kFront)); // CordRep::Unref(tree); // return edge; static CordRep* ExtractFront(CordRepBtree* tree); // Returns a tree containing the result of appending `right` to `left`. static CordRepBtree* MergeTrees(CordRepBtree* left, CordRepBtree* right); // Fallback functions for `Create()`, `Append()` and `Prepend()` which // deal with legacy / non conforming input, i.e.: CONCAT trees. static CordRepBtree* CreateSlow(CordRep* rep); static CordRepBtree* AppendSlow(CordRepBtree*, CordRep* rep); static CordRepBtree* PrependSlow(CordRepBtree*, CordRep* rep); // Recursively rebuilds `tree` into `stack`. If 'consume` is set to true, the // function will consume a reference on `tree`. `stack` is a null terminated // array containing the new tree's state, with the current leaf node at // stack[0], and parent nodes above that, or null for 'top of tree'. static void Rebuild(CordRepBtree** stack, CordRepBtree* tree, bool consume); // Aligns existing edges to start at index 0, to allow for a new edge to be // added to the back of the current edges. inline void AlignBegin(); // Aligns existing edges to end at `capacity`, to allow for a new edge to be // added in front of the current edges. inline void AlignEnd(); // Adds the provided edge to this node. // Requires this node to have capacity for the edge. Realigns / moves // existing edges as needed to prepend or append the new edge. template inline void Add(CordRep* rep); // Adds the provided edges to this node. // Requires this node to have capacity for the edges. Realigns / moves // existing edges as needed to prepend or append the new edges. template inline void Add(absl::Span); // Adds data from `data` to this node until either all data has been consumed, // or there is no more capacity for additional flat nodes inside this node. // Requires the current node to be a leaf node, data to be non empty, and the // current node to have capacity for at least one more data edge. // Returns any remaining data from `data` that was not added, which is // depending on the edge type (front / back) either the remaining prefix of // suffix of the input. // See the `Append/Prepend` function for the meaning and purpose of `extra`. template absl::string_view AddData(absl::string_view data, size_t extra); // Replace the front or back edge with the provided value. // Adopts a reference on `edge` and unrefs the old edge. template inline void SetEdge(CordRep* edge); // Returns a partial copy of the current tree containing the first `n` bytes // of data. `CopyResult` contains both the resulting edge and its height. The // resulting tree may be less high than the current tree, or even be a single // matching data edge if `allow_folding` is set to true. // For example, if `n == 1`, then the result will be the single data edge, and // height will be set to -1 (one below the owning leaf node). If n == 0, this // function returns null. Requires `n <= length` CopyResult CopyPrefix(size_t n, bool allow_folding = true); // Returns a partial copy of the current tree containing all data starting // after `offset`. `CopyResult` contains both the resulting edge and its // height. The resulting tree may be less high than the current tree, or even // be a single matching data edge. For example, if `n == length - 1`, then the // result will be a single data edge, and height will be set to -1 (one below // the owning leaf node). // Requires `offset < length` CopyResult CopySuffix(size_t offset); // Returns a OpResult value of {this, kSelf} or {Copy(), kCopied} // depending on the value of `owned`. inline OpResult ToOpResult(bool owned); // Adds `rep` to the specified tree, returning the modified tree. template static CordRepBtree* AddCordRep(CordRepBtree* tree, CordRep* rep); // Adds `data` to the specified tree, returning the modified tree. // See the `Append/Prepend` function for the meaning and purpose of `extra`. template static CordRepBtree* AddData(CordRepBtree* tree, absl::string_view data, size_t extra = 0); // Merges `src` into `dst` with `src` being added either before (kFront) or // after (kBack) `dst`. Requires the height of `dst` to be greater than or // equal to the height of `src`. template static CordRepBtree* Merge(CordRepBtree* dst, CordRepBtree* src); // Fallback version of GetAppendBuffer for large trees: GetAppendBuffer() // implements an inlined version for trees of limited height (3 levels), // GetAppendBufferSlow implements the logic for large trees. Span GetAppendBufferSlow(size_t size); // `edges_` contains all edges starting from this instance. // These are explicitly `child` edges only, a cord btree (or any cord tree in // that respect) does not store `parent` pointers anywhere: multiple trees / // parents can reference the same shared child edge. The type of these edges // depends on the height of the node. `Leaf nodes` (height == 0) contain `data // edges` (external or flat nodes, or sub-strings thereof). All other nodes // (height > 0) contain pointers to BTREE nodes with a height of `height - 1`. CordRep* edges_[kMaxCapacity]; friend class CordRepBtreeTestPeer; friend class CordRepBtreeNavigator; }; inline CordRepBtree* CordRep::btree() { assert(IsBtree()); return static_cast(this); } inline const CordRepBtree* CordRep::btree() const { assert(IsBtree()); return static_cast(this); } inline void CordRepBtree::InitInstance(int height, size_t begin, size_t end) { tag = BTREE; storage[0] = static_cast(height); storage[1] = static_cast(begin); storage[2] = static_cast(end); } inline CordRep* CordRepBtree::Edge(size_t index) const { assert(index >= begin()); assert(index < end()); return edges_[index]; } inline CordRep* CordRepBtree::Edge(EdgeType edge_type) const { return edges_[edge_type == kFront ? begin() : back()]; } inline absl::Span CordRepBtree::Edges() const { return {edges_ + begin(), size()}; } inline absl::Span CordRepBtree::Edges(size_t begin, size_t end) const { assert(begin <= end); assert(begin >= this->begin()); assert(end <= this->end()); return {edges_ + begin, static_cast(end - begin)}; } inline absl::string_view CordRepBtree::Data(size_t index) const { assert(height() == 0); return EdgeData(Edge(index)); } inline CordRepBtree* CordRepBtree::New(int height) { CordRepBtree* tree = new CordRepBtree; tree->length = 0; tree->InitInstance(height); return tree; } inline CordRepBtree* CordRepBtree::New(CordRep* rep) { CordRepBtree* tree = new CordRepBtree; int height = rep->IsBtree() ? rep->btree()->height() + 1 : 0; tree->length = rep->length; tree->InitInstance(height, /*begin=*/0, /*end=*/1); tree->edges_[0] = rep; return tree; } inline CordRepBtree* CordRepBtree::New(CordRepBtree* front, CordRepBtree* back) { assert(front->height() == back->height()); CordRepBtree* tree = new CordRepBtree; tree->length = front->length + back->length; tree->InitInstance(front->height() + 1, /*begin=*/0, /*end=*/2); tree->edges_[0] = front; tree->edges_[1] = back; return tree; } inline void CordRepBtree::Unref(absl::Span edges) { for (CordRep* edge : edges) { if (ABSL_PREDICT_FALSE(!edge->refcount.Decrement())) { CordRep::Destroy(edge); } } } inline CordRepBtree* CordRepBtree::CopyRaw(size_t new_length) const { CordRepBtree* tree = new CordRepBtree; // `length` and `refcount` are the first members of `CordRepBtree`. // We initialize `length` using the given length, have `refcount` be set to // ref = 1 through its default constructor, and copy all data beyond // 'refcount' which starts with `tag` using a single memcpy: all contents // except `refcount` is trivially copyable, and the compiler does not // efficiently coalesce member-wise copy of these members. // See https://gcc.godbolt.org/z/qY8zsca6z // # LINT.IfChange(copy_raw) tree->length = new_length; uint8_t* dst = &tree->tag; const uint8_t* src = &tag; const ptrdiff_t offset = src - reinterpret_cast(this); memcpy(dst, src, sizeof(CordRepBtree) - static_cast(offset)); return tree; // # LINT.ThenChange() } inline CordRepBtree* CordRepBtree::Copy() const { CordRepBtree* tree = CopyRaw(length); for (CordRep* rep : Edges()) CordRep::Ref(rep); return tree; } inline CordRepBtree* CordRepBtree::CopyToEndFrom(size_t begin, size_t new_length) const { assert(begin >= this->begin()); assert(begin <= this->end()); CordRepBtree* tree = CopyRaw(new_length); tree->set_begin(begin); for (CordRep* edge : tree->Edges()) CordRep::Ref(edge); return tree; } inline CordRepBtree* CordRepBtree::CopyBeginTo(size_t end, size_t new_length) const { assert(end <= capacity()); assert(end >= this->begin()); CordRepBtree* tree = CopyRaw(new_length); tree->set_end(end); for (CordRep* edge : tree->Edges()) CordRep::Ref(edge); return tree; } inline void CordRepBtree::AlignBegin() { // The below code itself does not need to be fast as typically we have // mono-directional append/prepend calls, and `begin` / `end` are typically // adjusted no more than once. But we want to avoid potential register clobber // effects, making the compiler emit register save/store/spills, and minimize // the size of code. const size_t delta = begin(); if (ABSL_PREDICT_FALSE(delta != 0)) { const size_t new_end = end() - delta; set_begin(0); set_end(new_end); // TODO(mvels): we can write this using 2 loads / 2 stores depending on // total size for the kMaxCapacity = 6 case. I.e., we can branch (switch) on // size, and then do overlapping load/store of up to 4 pointers (inlined as // XMM, YMM or ZMM load/store) and up to 2 pointers (XMM / YMM), which is a) // compact and b) not clobbering any registers. ABSL_ASSUME(new_end <= kMaxCapacity); #ifdef __clang__ #pragma unroll 1 #endif for (size_t i = 0; i < new_end; ++i) { edges_[i] = edges_[i + delta]; } } } inline void CordRepBtree::AlignEnd() { // See comments in `AlignBegin` for motivation on the hand-rolled for loops. const size_t delta = capacity() - end(); if (delta != 0) { const size_t new_begin = begin() + delta; const size_t new_end = end() + delta; set_begin(new_begin); set_end(new_end); ABSL_ASSUME(new_end <= kMaxCapacity); #ifdef __clang__ #pragma unroll 1 #endif for (size_t i = new_end - 1; i >= new_begin; --i) { edges_[i] = edges_[i - delta]; } } } template <> inline void CordRepBtree::Add(CordRep* rep) { AlignBegin(); edges_[fetch_add_end(1)] = rep; } template <> inline void CordRepBtree::Add( absl::Span edges) { AlignBegin(); size_t new_end = end(); for (CordRep* edge : edges) edges_[new_end++] = edge; set_end(new_end); } template <> inline void CordRepBtree::Add(CordRep* rep) { AlignEnd(); edges_[sub_fetch_begin(1)] = rep; } template <> inline void CordRepBtree::Add( absl::Span edges) { AlignEnd(); size_t new_begin = begin() - edges.size(); set_begin(new_begin); for (CordRep* edge : edges) edges_[new_begin++] = edge; } template inline void CordRepBtree::SetEdge(CordRep* edge) { const int idx = edge_type == kFront ? begin() : back(); CordRep::Unref(edges_[idx]); edges_[idx] = edge; } inline CordRepBtree::OpResult CordRepBtree::ToOpResult(bool owned) { return owned ? OpResult{this, kSelf} : OpResult{Copy(), kCopied}; } inline CordRepBtree::Position CordRepBtree::IndexOf(size_t offset) const { assert(offset < length); size_t index = begin(); while (offset >= edges_[index]->length) offset -= edges_[index++]->length; return {index, offset}; } inline CordRepBtree::Position CordRepBtree::IndexBefore(size_t offset) const { assert(offset > 0); assert(offset <= length); size_t index = begin(); while (offset > edges_[index]->length) offset -= edges_[index++]->length; return {index, offset}; } inline CordRepBtree::Position CordRepBtree::IndexBefore(Position front, size_t offset) const { size_t index = front.index; offset = offset + front.n; while (offset > edges_[index]->length) offset -= edges_[index++]->length; return {index, offset}; } inline CordRepBtree::Position CordRepBtree::IndexOfLength(size_t n) const { assert(n <= length); size_t index = back(); size_t strip = length - n; while (strip >= edges_[index]->length) strip -= edges_[index--]->length; return {index, edges_[index]->length - strip}; } inline CordRepBtree::Position CordRepBtree::IndexBeyond( const size_t offset) const { // We need to find the edge which `starting offset` is beyond (>=)`offset`. // For this we can't use the `offset -= length` logic of IndexOf. Instead, we // track the offset of the `current edge` in `off`, which we increase as we // iterate over the edges until we find the matching edge. size_t off = 0; size_t index = begin(); while (offset > off) off += edges_[index++]->length; return {index, off - offset}; } inline CordRepBtree* CordRepBtree::Create(CordRep* rep) { if (IsDataEdge(rep)) return New(rep); return CreateSlow(rep); } inline Span CordRepBtree::GetAppendBuffer(size_t size) { assert(refcount.IsOne()); CordRepBtree* tree = this; const int height = this->height(); CordRepBtree* n1 = tree; CordRepBtree* n2 = tree; CordRepBtree* n3 = tree; switch (height) { case 3: tree = tree->Edge(kBack)->btree(); if (!tree->refcount.IsOne()) return {}; n2 = tree; ABSL_FALLTHROUGH_INTENDED; case 2: tree = tree->Edge(kBack)->btree(); if (!tree->refcount.IsOne()) return {}; n1 = tree; ABSL_FALLTHROUGH_INTENDED; case 1: tree = tree->Edge(kBack)->btree(); if (!tree->refcount.IsOne()) return {}; ABSL_FALLTHROUGH_INTENDED; case 0: CordRep* edge = tree->Edge(kBack); if (!edge->refcount.IsOne()) return {}; if (edge->tag < FLAT) return {}; size_t avail = edge->flat()->Capacity() - edge->length; if (avail == 0) return {}; size_t delta = (std::min)(size, avail); Span span = {edge->flat()->Data() + edge->length, delta}; edge->length += delta; switch (height) { case 3: n3->length += delta; ABSL_FALLTHROUGH_INTENDED; case 2: n2->length += delta; ABSL_FALLTHROUGH_INTENDED; case 1: n1->length += delta; ABSL_FALLTHROUGH_INTENDED; case 0: tree->length += delta; return span; } break; } return GetAppendBufferSlow(size); } extern template CordRepBtree* CordRepBtree::AddCordRep( CordRepBtree* tree, CordRep* rep); extern template CordRepBtree* CordRepBtree::AddCordRep( CordRepBtree* tree, CordRep* rep); inline CordRepBtree* CordRepBtree::Append(CordRepBtree* tree, CordRep* rep) { if (ABSL_PREDICT_TRUE(IsDataEdge(rep))) { return CordRepBtree::AddCordRep(tree, rep); } return AppendSlow(tree, rep); } inline CordRepBtree* CordRepBtree::Prepend(CordRepBtree* tree, CordRep* rep) { if (ABSL_PREDICT_TRUE(IsDataEdge(rep))) { return CordRepBtree::AddCordRep(tree, rep); } return PrependSlow(tree, rep); } #ifdef NDEBUG inline CordRepBtree* CordRepBtree::AssertValid(CordRepBtree* tree, bool /* shallow */) { return tree; } inline const CordRepBtree* CordRepBtree::AssertValid(const CordRepBtree* tree, bool /* shallow */) { return tree; } #endif } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cord_internal.h0000644000175000017510000010005214737212474024640 0ustar nileshnilesh// Copyright 2021 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ #define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/invoke.h" #include "absl/base/optimization.h" #include "absl/container/internal/compressed_tuple.h" #include "absl/container/internal/container_memory.h" #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" // We can only add poisoning if we can detect consteval executions. #if defined(ABSL_HAVE_CONSTANT_EVALUATED) && \ (defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER)) #define ABSL_INTERNAL_CORD_HAVE_SANITIZER 1 #endif #define ABSL_CORD_INTERNAL_NO_SANITIZE \ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // The overhead of a vtable is too much for Cord, so we roll our own subclasses // using only a single byte to differentiate classes from each other - the "tag" // byte. Define the subclasses first so we can provide downcasting helper // functions in the base class. struct CordRep; struct CordRepConcat; struct CordRepExternal; struct CordRepFlat; struct CordRepSubstring; struct CordRepCrc; class CordRepRing; class CordRepBtree; class CordzInfo; // Default feature enable states for cord ring buffers enum CordFeatureDefaults { kCordEnableRingBufferDefault = false, kCordShallowSubcordsDefault = false }; extern std::atomic cord_ring_buffer_enabled; extern std::atomic shallow_subcords_enabled; inline void enable_cord_ring_buffer(bool enable) { cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed); } inline void enable_shallow_subcords(bool enable) { shallow_subcords_enabled.store(enable, std::memory_order_relaxed); } enum Constants { // The inlined size to use with absl::InlinedVector. // // Note: The InlinedVectors in this file (and in cord.h) do not need to use // the same value for their inlined size. The fact that they do is historical. // It may be desirable for each to use a different inlined size optimized for // that InlinedVector's usage. // // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for // the inlined vector size (47 exists for backward compatibility). kInlinedVectorSize = 47, // Prefer copying blocks of at most this size, otherwise reference count. kMaxBytesToCopy = 511 }; // Emits a fatal error "Unexpected node type: xyz" and aborts the program. ABSL_ATTRIBUTE_NORETURN void LogFatalNodeType(CordRep* rep); // Fast implementation of memmove for up to 15 bytes. This implementation is // safe for overlapping regions. If nullify_tail is true, the destination is // padded with '\0' up to 15 bytes. template inline void SmallMemmove(char* dst, const char* src, size_t n) { if (n >= 8) { assert(n <= 15); uint64_t buf1; uint64_t buf2; memcpy(&buf1, src, 8); memcpy(&buf2, src + n - 8, 8); if (nullify_tail) { memset(dst + 7, 0, 8); } memcpy(dst, &buf1, 8); memcpy(dst + n - 8, &buf2, 8); } else if (n >= 4) { uint32_t buf1; uint32_t buf2; memcpy(&buf1, src, 4); memcpy(&buf2, src + n - 4, 4); if (nullify_tail) { memset(dst + 4, 0, 4); memset(dst + 7, 0, 8); } memcpy(dst, &buf1, 4); memcpy(dst + n - 4, &buf2, 4); } else { if (n != 0) { dst[0] = src[0]; dst[n / 2] = src[n / 2]; dst[n - 1] = src[n - 1]; } if (nullify_tail) { memset(dst + 7, 0, 8); memset(dst + n, 0, 8); } } } // Compact class for tracking the reference count and state flags for CordRep // instances. Data is stored in an atomic int32_t for compactness and speed. class RefcountAndFlags { public: constexpr RefcountAndFlags() : count_{kRefIncrement} {} struct Immortal {}; explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {} // Increments the reference count. Imposes no memory ordering. inline void Increment() { count_.fetch_add(kRefIncrement, std::memory_order_relaxed); } // Asserts that the current refcount is greater than 0. If the refcount is // greater than 1, decrements the reference count. // // Returns false if there are no references outstanding; true otherwise. // Inserts barriers to ensure that state written before this method returns // false will be visible to a thread that just observed this method returning // false. Always returns false when the immortal bit is set. inline bool Decrement() { int32_t refcount = count_.load(std::memory_order_acquire); assert((refcount & kRefcountMask) > 0 || refcount & kImmortalFlag); return refcount != kRefIncrement && (count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & kHighRefcountMask) != 0; } // Same as Decrement but expect that refcount is greater than 1. inline bool DecrementExpectHighRefcount() { int32_t refcount = count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel); assert((refcount & kRefcountMask) > 0 || refcount & kImmortalFlag); return (refcount & kHighRefcountMask) != 0; } // Returns the current reference count using acquire semantics. inline size_t Get() const { return static_cast(count_.load(std::memory_order_acquire) >> kNumFlags); } // Returns whether the atomic integer is 1. // If the reference count is used in the conventional way, a // reference count of 1 implies that the current thread owns the // reference and no other thread shares it. // This call performs the test for a reference count of one, and // performs the memory barrier needed for the owning thread // to act on the object, knowing that it has exclusive access to the // object. Always returns false when the immortal bit is set. inline bool IsOne() { return (count_.load(std::memory_order_acquire) & kRefcountMask) == kRefIncrement; } bool IsImmortal() const { return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0; } private: // We reserve the bottom bits for flags. // kImmortalBit indicates that this entity should never be collected; it is // used for the StringConstant constructor to avoid collecting immutable // constant cords. // kReservedFlag is reserved for future use. enum Flags { kNumFlags = 2, kImmortalFlag = 0x1, kReservedFlag = 0x2, kRefIncrement = (1 << kNumFlags), // Bitmask to use when checking refcount by equality. This masks out // all flags except kImmortalFlag, which is part of the refcount for // purposes of equality. (A refcount of 0 or 1 does not count as 0 or 1 // if the immortal bit is set.) kRefcountMask = ~kReservedFlag, // Bitmask to use when checking if refcount is equal to 1 and not // immortal when decrementing the refcount. This masks out kRefIncrement and // all flags except kImmortalFlag. If the masked RefcountAndFlags is 0, we // assume the refcount is equal to 1, since we know it's not immortal and // not greater than 1. If the masked RefcountAndFlags is not 0, we can // assume the refcount is not equal to 1 since either a higher bit in the // refcount is set, or kImmortal is set. kHighRefcountMask = kRefcountMask & ~kRefIncrement, }; std::atomic count_; }; // Various representations that we allow enum CordRepKind { UNUSED_0 = 0, SUBSTRING = 1, CRC = 2, BTREE = 3, RING = 4, EXTERNAL = 5, // We have different tags for different sized flat arrays, // starting with FLAT, and limited to MAX_FLAT_TAG. The below values map to an // allocated range of 32 bytes to 256 KB. The current granularity is: // - 8 byte granularity for flat sizes in [32 - 512] // - 64 byte granularity for flat sizes in (512 - 8KiB] // - 4KiB byte granularity for flat sizes in (8KiB, 256 KiB] // If a new tag is needed in the future, then 'FLAT' and 'MAX_FLAT_TAG' should // be adjusted as well as the Tag <---> Size mapping logic so that FLAT still // represents the minimum flat allocation size. (32 bytes as of now). FLAT = 6, MAX_FLAT_TAG = 248 }; // There are various locations where we want to check if some rep is a 'plain' // data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we // can perform this check in a single branch as 'tag >= EXTERNAL' // Likewise, we have some locations where we check for 'ring or external/flat', // so likewise align RING to EXTERNAL. // Note that we can leave this optimization to the compiler. The compiler will // DTRT when it sees a condition like `tag == EXTERNAL || tag >= FLAT`. static_assert(RING == BTREE + 1, "BTREE and RING not consecutive"); static_assert(EXTERNAL == RING + 1, "BTREE and EXTERNAL not consecutive"); static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive"); struct CordRep { // Result from an `extract edge` operation. Contains the (possibly changed) // tree node as well as the extracted edge, or {tree, nullptr} if no edge // could be extracted. // On success, the returned `tree` value is null if `extracted` was the only // data edge inside the tree, a data edge if there were only two data edges in // the tree, or the (possibly new / smaller) remaining tree with the extracted // data edge removed. struct ExtractResult { CordRep* tree; CordRep* extracted; }; CordRep() = default; constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l) : length(l), refcount(immortal), tag(EXTERNAL), storage{} {} // The following three fields have to be less than 32 bytes since // that is the smallest supported flat node size. Some code optimizations rely // on the specific layout of these fields. Notably: the non-trivial field // `refcount` being preceded by `length`, and being tailed by POD data // members only. // # LINT.IfChange size_t length; RefcountAndFlags refcount; // If tag < FLAT, it represents CordRepKind and indicates the type of node. // Otherwise, the node type is CordRepFlat and the tag is the encoded size. uint8_t tag; // `storage` provides two main purposes: // - the starting point for FlatCordRep.Data() [flexible-array-member] // - 3 bytes of additional storage for use by derived classes. // The latter is used by CordrepConcat and CordRepBtree. CordRepConcat stores // a 'depth' value in storage[0], and the (future) CordRepBtree class stores // `height`, `begin` and `end` in the 3 entries. Otherwise we would need to // allocate room for these in the derived class, as not all compilers reuse // padding space from the base class (clang and gcc do, MSVC does not, etc) uint8_t storage[3]; // # LINT.ThenChange(cord_rep_btree.h:copy_raw) // Returns true if this instance's tag matches the requested type. constexpr bool IsRing() const { return tag == RING; } constexpr bool IsSubstring() const { return tag == SUBSTRING; } constexpr bool IsCrc() const { return tag == CRC; } constexpr bool IsExternal() const { return tag == EXTERNAL; } constexpr bool IsFlat() const { return tag >= FLAT; } constexpr bool IsBtree() const { return tag == BTREE; } inline CordRepRing* ring(); inline const CordRepRing* ring() const; inline CordRepSubstring* substring(); inline const CordRepSubstring* substring() const; inline CordRepCrc* crc(); inline const CordRepCrc* crc() const; inline CordRepExternal* external(); inline const CordRepExternal* external() const; inline CordRepFlat* flat(); inline const CordRepFlat* flat() const; inline CordRepBtree* btree(); inline const CordRepBtree* btree() const; // -------------------------------------------------------------------- // Memory management // Destroys the provided `rep`. static void Destroy(CordRep* rep); // Increments the reference count of `rep`. // Requires `rep` to be a non-null pointer value. static inline CordRep* Ref(CordRep* rep); // Decrements the reference count of `rep`. Destroys rep if count reaches // zero. Requires `rep` to be a non-null pointer value. static inline void Unref(CordRep* rep); }; struct CordRepSubstring : public CordRep { size_t start; // Starting offset of substring in child CordRep* child; // Creates a substring on `child`, adopting a reference on `child`. // Requires `child` to be either a flat or external node, and `pos` and `n` to // form a non-empty partial sub range of `'child`, i.e.: // `n > 0 && n < length && n + pos <= length` static inline CordRepSubstring* Create(CordRep* child, size_t pos, size_t n); // Creates a substring of `rep`. Does not adopt a reference on `rep`. // Requires `IsDataEdge(rep) && n > 0 && pos + n <= rep->length`. // If `n == rep->length` then this method returns `CordRep::Ref(rep)` // If `rep` is a substring of a flat or external node, then this method will // return a new substring of that flat or external node with `pos` adjusted // with the original `start` position. static inline CordRep* Substring(CordRep* rep, size_t pos, size_t n); }; // Type for function pointer that will invoke the releaser function and also // delete the `CordRepExternalImpl` corresponding to the passed in // `CordRepExternal`. using ExternalReleaserInvoker = void (*)(CordRepExternal*); // External CordReps are allocated together with a type erased releaser. The // releaser is stored in the memory directly following the CordRepExternal. struct CordRepExternal : public CordRep { CordRepExternal() = default; explicit constexpr CordRepExternal(absl::string_view str) : CordRep(RefcountAndFlags::Immortal{}, str.size()), base(str.data()), releaser_invoker(nullptr) {} const char* base; // Pointer to function that knows how to call and destroy the releaser. ExternalReleaserInvoker releaser_invoker; // Deletes (releases) the external rep. // Requires rep != nullptr and rep->IsExternal() static void Delete(CordRep* rep); }; struct Rank1 {}; struct Rank0 : Rank1 {}; template > void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) { ::absl::base_internal::invoke(std::forward(releaser), data); } template > void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) { ::absl::base_internal::invoke(std::forward(releaser)); } // We use CompressedTuple so that we can benefit from EBCO. template struct CordRepExternalImpl : public CordRepExternal, public ::absl::container_internal::CompressedTuple { // The extra int arg is so that we can avoid interfering with copy/move // constructors while still benefitting from perfect forwarding. template CordRepExternalImpl(T&& releaser, int) : CordRepExternalImpl::CompressedTuple(std::forward(releaser)) { this->releaser_invoker = &Release; } ~CordRepExternalImpl() { InvokeReleaser(Rank0{}, std::move(this->template get<0>()), absl::string_view(base, length)); } static void Release(CordRepExternal* rep) { delete static_cast(rep); } }; inline CordRepSubstring* CordRepSubstring::Create(CordRep* child, size_t pos, size_t n) { assert(child != nullptr); assert(n > 0); assert(n < child->length); assert(pos < child->length); assert(n <= child->length - pos); // TODO(b/217376272): Harden internal logic. // Move to strategical places inside the Cord logic and make this an assert. if (ABSL_PREDICT_FALSE(!(child->IsExternal() || child->IsFlat()))) { LogFatalNodeType(child); } CordRepSubstring* rep = new CordRepSubstring(); rep->length = n; rep->tag = SUBSTRING; rep->start = pos; rep->child = child; return rep; } inline CordRep* CordRepSubstring::Substring(CordRep* rep, size_t pos, size_t n) { assert(rep != nullptr); assert(n != 0); assert(pos < rep->length); assert(n <= rep->length - pos); if (n == rep->length) return CordRep::Ref(rep); if (rep->IsSubstring()) { pos += rep->substring()->start; rep = rep->substring()->child; } CordRepSubstring* substr = new CordRepSubstring(); substr->length = n; substr->tag = SUBSTRING; substr->start = pos; substr->child = CordRep::Ref(rep); return substr; } inline void CordRepExternal::Delete(CordRep* rep) { assert(rep != nullptr && rep->IsExternal()); auto* rep_external = static_cast(rep); assert(rep_external->releaser_invoker != nullptr); rep_external->releaser_invoker(rep_external); } template struct ConstInitExternalStorage { ABSL_CONST_INIT static CordRepExternal value; }; template ABSL_CONST_INIT CordRepExternal ConstInitExternalStorage::value(Str::value); enum { kMaxInline = 15, }; constexpr char GetOrNull(absl::string_view data, size_t pos) { return pos < data.size() ? data[pos] : '\0'; } // We store cordz_info as 64 bit pointer value in little endian format. This // guarantees that the least significant byte of cordz_info matches the first // byte of the inline data representation in `data`, which holds the inlined // size or the 'is_tree' bit. using cordz_info_t = int64_t; // Assert that the `cordz_info` pointer value perfectly overlaps the last half // of `data` and can hold a pointer value. static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, ""); static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), ""); // LittleEndianByte() creates a little endian representation of 'value', i.e.: // a little endian value where the first byte in the host's representation // holds 'value`, with all other bytes being 0. static constexpr cordz_info_t LittleEndianByte(unsigned char value) { #if defined(ABSL_IS_BIG_ENDIAN) return static_cast(value) << ((sizeof(cordz_info_t) - 1) * 8); #else return value; #endif } class InlineData { public: // DefaultInitType forces the use of the default initialization constructor. enum DefaultInitType { kDefaultInit }; // kNullCordzInfo holds the little endian representation of intptr_t(1) // This is the 'null' / initial value of 'cordz_info'. The null value // is specifically big endian 1 as with 64-bit pointers, the last // byte of cordz_info overlaps with the last byte holding the tag. static constexpr cordz_info_t kNullCordzInfo = LittleEndianByte(1); // kTagOffset contains the offset of the control byte / tag. This constant is // intended mostly for debugging purposes: do not remove this constant as it // is actively inspected and used by gdb pretty printing code. static constexpr size_t kTagOffset = 0; // Implement `~InlineData()` conditionally: we only need this destructor to // unpoison poisoned instances under *SAN, and it will only compile correctly // if the current compiler supports `absl::is_constant_evaluated()`. #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER ~InlineData() noexcept { unpoison(); } #endif constexpr InlineData() noexcept { poison_this(); } explicit InlineData(DefaultInitType) noexcept : rep_(kDefaultInit) { poison_this(); } explicit InlineData(CordRep* rep) noexcept : rep_(rep) { ABSL_ASSERT(rep != nullptr); } // Explicit constexpr constructor to create a constexpr InlineData // value. Creates an inlined SSO value if `rep` is null, otherwise // creates a tree instance value. constexpr InlineData(absl::string_view sv, CordRep* rep) noexcept : rep_(rep ? Rep(rep) : Rep(sv)) { poison(); } constexpr InlineData(const InlineData& rhs) noexcept; InlineData& operator=(const InlineData& rhs) noexcept; friend bool operator==(const InlineData& lhs, const InlineData& rhs) { #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER const Rep l = lhs.rep_.SanitizerSafeCopy(); const Rep r = rhs.rep_.SanitizerSafeCopy(); return memcmp(&l, &r, sizeof(l)) == 0; #else return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; #endif } friend bool operator!=(const InlineData& lhs, const InlineData& rhs) { return !operator==(lhs, rhs); } // Poisons the unused inlined SSO data if the current instance // is inlined, else un-poisons the entire instance. constexpr void poison(); // Un-poisons this instance. constexpr void unpoison(); // Poisons the current instance. This is used on default initialization. constexpr void poison_this(); // Returns true if the current instance is empty. // The 'empty value' is an inlined data value of zero length. bool is_empty() const { return rep_.tag() == 0; } // Returns true if the current instance holds a tree value. bool is_tree() const { return (rep_.tag() & 1) != 0; } // Returns true if the current instance holds a cordz_info value. // Requires the current instance to hold a tree value. bool is_profiled() const { assert(is_tree()); return rep_.cordz_info() != kNullCordzInfo; } // Returns true if either of the provided instances hold a cordz_info value. // This method is more efficient than the equivalent `data1.is_profiled() || // data2.is_profiled()`. Requires both arguments to hold a tree. static bool is_either_profiled(const InlineData& data1, const InlineData& data2) { assert(data1.is_tree() && data2.is_tree()); return (data1.rep_.cordz_info() | data2.rep_.cordz_info()) != kNullCordzInfo; } // Returns the cordz_info sampling instance for this instance, or nullptr // if the current instance is not sampled and does not have CordzInfo data. // Requires the current instance to hold a tree value. CordzInfo* cordz_info() const { assert(is_tree()); intptr_t info = static_cast(absl::little_endian::ToHost64( static_cast(rep_.cordz_info()))); assert(info & 1); return reinterpret_cast(info - 1); } // Sets the current cordz_info sampling instance for this instance, or nullptr // if the current instance is not sampled and does not have CordzInfo data. // Requires the current instance to hold a tree value. void set_cordz_info(CordzInfo* cordz_info) { assert(is_tree()); uintptr_t info = reinterpret_cast(cordz_info) | 1; rep_.set_cordz_info( static_cast(absl::little_endian::FromHost64(info))); } // Resets the current cordz_info to null / empty. void clear_cordz_info() { assert(is_tree()); rep_.set_cordz_info(kNullCordzInfo); } // Returns a read only pointer to the character data inside this instance. // Requires the current instance to hold inline data. const char* as_chars() const { assert(!is_tree()); return rep_.as_chars(); } // Returns a mutable pointer to the character data inside this instance. // Should be used for 'write only' operations setting an inlined value. // Applications can set the value of inlined data either before or after // setting the inlined size, i.e., both of the below are valid: // // // Set inlined data and inline size // memcpy(data_.as_chars(), data, size); // data_.set_inline_size(size); // // // Set inlined size and inline data // data_.set_inline_size(size); // memcpy(data_.as_chars(), data, size); // // It's an error to read from the returned pointer without a preceding write // if the current instance does not hold inline data, i.e.: is_tree() == true. char* as_chars() { return rep_.as_chars(); } // Returns the tree value of this value. // Requires the current instance to hold a tree value. CordRep* as_tree() const { assert(is_tree()); return rep_.tree(); } void set_inline_data(const char* data, size_t n) { ABSL_ASSERT(n <= kMaxInline); unpoison(); rep_.set_tag(static_cast(n << 1)); SmallMemmove(rep_.as_chars(), data, n); poison(); } void copy_max_inline_to(char* dst) const { assert(!is_tree()); memcpy(dst, rep_.SanitizerSafeCopy().as_chars(), kMaxInline); } // Initialize this instance to holding the tree value `rep`, // initializing the cordz_info to null, i.e.: 'not profiled'. void make_tree(CordRep* rep) { unpoison(); rep_.make_tree(rep); } // Set the tree value of this instance to 'rep`. // Requires the current instance to already hold a tree value. // Does not affect the value of cordz_info. void set_tree(CordRep* rep) { assert(is_tree()); rep_.set_tree(rep); } // Returns the size of the inlined character data inside this instance. // Requires the current instance to hold inline data. size_t inline_size() const { return rep_.inline_size(); } // Sets the size of the inlined character data inside this instance. // Requires `size` to be <= kMaxInline. // See the documentation on 'as_chars()' for more information and examples. void set_inline_size(size_t size) { unpoison(); rep_.set_inline_size(size); poison(); } // Compares 'this' inlined data with rhs. The comparison is a straightforward // lexicographic comparison. `Compare()` returns values as follows: // // -1 'this' InlineData instance is smaller // 0 the InlineData instances are equal // 1 'this' InlineData instance larger int Compare(const InlineData& rhs) const { return Compare(rep_.SanitizerSafeCopy(), rhs.rep_.SanitizerSafeCopy()); } private: struct Rep { // See cordz_info_t for forced alignment and size of `cordz_info` details. struct AsTree { explicit constexpr AsTree(absl::cord_internal::CordRep* tree) : rep(tree) {} cordz_info_t cordz_info = kNullCordzInfo; absl::cord_internal::CordRep* rep; }; explicit Rep(DefaultInitType) {} constexpr Rep() : data{0} {} constexpr Rep(const Rep&) = default; constexpr Rep& operator=(const Rep&) = default; explicit constexpr Rep(CordRep* rep) : as_tree(rep) {} explicit constexpr Rep(absl::string_view chars) : data{static_cast((chars.size() << 1)), GetOrNull(chars, 0), GetOrNull(chars, 1), GetOrNull(chars, 2), GetOrNull(chars, 3), GetOrNull(chars, 4), GetOrNull(chars, 5), GetOrNull(chars, 6), GetOrNull(chars, 7), GetOrNull(chars, 8), GetOrNull(chars, 9), GetOrNull(chars, 10), GetOrNull(chars, 11), GetOrNull(chars, 12), GetOrNull(chars, 13), GetOrNull(chars, 14)} {} // Disable sanitizer as we must always be able to read `tag`. ABSL_CORD_INTERNAL_NO_SANITIZE int8_t tag() const { return reinterpret_cast(this)[0]; } void set_tag(int8_t rhs) { reinterpret_cast(this)[0] = rhs; } char* as_chars() { return data + 1; } const char* as_chars() const { return data + 1; } bool is_tree() const { return (tag() & 1) != 0; } size_t inline_size() const { ABSL_ASSERT(!is_tree()); return static_cast(tag()) >> 1; } void set_inline_size(size_t size) { ABSL_ASSERT(size <= kMaxInline); set_tag(static_cast(size << 1)); } CordRep* tree() const { return as_tree.rep; } void set_tree(CordRep* rhs) { as_tree.rep = rhs; } cordz_info_t cordz_info() const { return as_tree.cordz_info; } void set_cordz_info(cordz_info_t rhs) { as_tree.cordz_info = rhs; } void make_tree(CordRep* tree) { as_tree.rep = tree; as_tree.cordz_info = kNullCordzInfo; } #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER constexpr Rep SanitizerSafeCopy() const { if (!absl::is_constant_evaluated()) { Rep res; if (is_tree()) { res = *this; } else { res.set_tag(tag()); memcpy(res.as_chars(), as_chars(), inline_size()); } return res; } else { return *this; } } #else constexpr const Rep& SanitizerSafeCopy() const { return *this; } #endif // If the data has length <= kMaxInline, we store it in `data`, and // store the size in the first char of `data` shifted left + 1. // Else we store it in a tree and store a pointer to that tree in // `as_tree.rep` with a tagged pointer to make `tag() & 1` non zero. union { char data[kMaxInline + 1]; AsTree as_tree; }; }; // Private implementation of `Compare()` static inline int Compare(const Rep& lhs, const Rep& rhs) { uint64_t x, y; memcpy(&x, lhs.as_chars(), sizeof(x)); memcpy(&y, rhs.as_chars(), sizeof(y)); if (x == y) { memcpy(&x, lhs.as_chars() + 7, sizeof(x)); memcpy(&y, rhs.as_chars() + 7, sizeof(y)); if (x == y) { if (lhs.inline_size() == rhs.inline_size()) return 0; return lhs.inline_size() < rhs.inline_size() ? -1 : 1; } } x = absl::big_endian::FromHost64(x); y = absl::big_endian::FromHost64(y); return x < y ? -1 : 1; } Rep rep_; }; static_assert(sizeof(InlineData) == kMaxInline + 1, ""); #ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER constexpr InlineData::InlineData(const InlineData& rhs) noexcept : rep_(rhs.rep_.SanitizerSafeCopy()) { poison(); } inline InlineData& InlineData::operator=(const InlineData& rhs) noexcept { unpoison(); rep_ = rhs.rep_.SanitizerSafeCopy(); poison(); return *this; } constexpr void InlineData::poison_this() { if (!absl::is_constant_evaluated()) { container_internal::SanitizerPoisonObject(this); } } constexpr void InlineData::unpoison() { if (!absl::is_constant_evaluated()) { container_internal::SanitizerUnpoisonObject(this); } } constexpr void InlineData::poison() { if (!absl::is_constant_evaluated()) { if (is_tree()) { container_internal::SanitizerUnpoisonObject(this); } else if (const size_t size = inline_size()) { if (size < kMaxInline) { const char* end = rep_.as_chars() + size; container_internal::SanitizerPoisonMemoryRegion(end, kMaxInline - size); } } else { container_internal::SanitizerPoisonObject(this); } } } #else // ABSL_INTERNAL_CORD_HAVE_SANITIZER constexpr InlineData::InlineData(const InlineData&) noexcept = default; inline InlineData& InlineData::operator=(const InlineData&) noexcept = default; constexpr void InlineData::poison_this() {} constexpr void InlineData::unpoison() {} constexpr void InlineData::poison() {} #endif // ABSL_INTERNAL_CORD_HAVE_SANITIZER inline CordRepSubstring* CordRep::substring() { assert(IsSubstring()); return static_cast(this); } inline const CordRepSubstring* CordRep::substring() const { assert(IsSubstring()); return static_cast(this); } inline CordRepExternal* CordRep::external() { assert(IsExternal()); return static_cast(this); } inline const CordRepExternal* CordRep::external() const { assert(IsExternal()); return static_cast(this); } inline CordRep* CordRep::Ref(CordRep* rep) { // ABSL_ASSUME is a workaround for // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105585 ABSL_ASSUME(rep != nullptr); rep->refcount.Increment(); return rep; } inline void CordRep::Unref(CordRep* rep) { assert(rep != nullptr); // Expect refcount to be 0. Avoiding the cost of an atomic decrement should // typically outweigh the cost of an extra branch checking for ref == 1. if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) { Destroy(rep); } } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cord_rep_btree.cc0000644000175000017510000012513514737212474025142 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/strings/internal/cord_rep_btree.h" #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_consume.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr size_t CordRepBtree::kMaxCapacity; #endif namespace { using NodeStack = CordRepBtree * [CordRepBtree::kMaxDepth]; using EdgeType = CordRepBtree::EdgeType; using OpResult = CordRepBtree::OpResult; using CopyResult = CordRepBtree::CopyResult; constexpr auto kFront = CordRepBtree::kFront; constexpr auto kBack = CordRepBtree::kBack; ABSL_CONST_INIT std::atomic cord_btree_exhaustive_validation(false); // Implementation of the various 'Dump' functions. // Prints the entire tree structure or 'rep'. External callers should // not specify 'depth' and leave it to its default (0) value. // Rep may be a CordRepBtree tree, or a SUBSTRING / EXTERNAL / FLAT node. void DumpAll(const CordRep* rep, bool include_contents, std::ostream& stream, size_t depth = 0) { // Allow for full height trees + substring -> flat / external nodes. assert(depth <= CordRepBtree::kMaxDepth + 2); std::string sharing = const_cast(rep)->refcount.IsOne() ? std::string("Private") : absl::StrCat("Shared(", rep->refcount.Get(), ")"); std::string sptr = absl::StrCat("0x", absl::Hex(rep)); // Dumps the data contents of `rep` if `include_contents` is true. // Always emits a new line character. auto maybe_dump_data = [&stream, include_contents](const CordRep* r) { if (include_contents) { // Allow for up to 60 wide display of content data, which with some // indentation and prefix / labels keeps us within roughly 80-100 wide. constexpr size_t kMaxDataLength = 60; stream << ", data = \"" << EdgeData(r).substr(0, kMaxDataLength) << (r->length > kMaxDataLength ? "\"..." : "\""); } stream << '\n'; }; // For each level, we print the 'shared/private' state and the rep pointer, // indented by two spaces per recursive depth. stream << std::string(depth * 2, ' ') << sharing << " (" << sptr << ") "; if (rep->IsBtree()) { const CordRepBtree* node = rep->btree(); std::string label = node->height() ? absl::StrCat("Node(", node->height(), ")") : "Leaf"; stream << label << ", len = " << node->length << ", begin = " << node->begin() << ", end = " << node->end() << "\n"; for (CordRep* edge : node->Edges()) { DumpAll(edge, include_contents, stream, depth + 1); } } else if (rep->tag == SUBSTRING) { const CordRepSubstring* substring = rep->substring(); stream << "Substring, len = " << rep->length << ", start = " << substring->start; maybe_dump_data(rep); DumpAll(substring->child, include_contents, stream, depth + 1); } else if (rep->tag >= FLAT) { stream << "Flat, len = " << rep->length << ", cap = " << rep->flat()->Capacity(); maybe_dump_data(rep); } else if (rep->tag == EXTERNAL) { stream << "Extn, len = " << rep->length; maybe_dump_data(rep); } } // TODO(b/192061034): add 'bytes to copy' logic to avoid large slop on substring // small data out of large reps, and general efficiency of 'always copy small // data'. Consider making this a cord rep internal library function. CordRepSubstring* CreateSubstring(CordRep* rep, size_t offset, size_t n) { assert(n != 0); assert(offset + n <= rep->length); assert(offset != 0 || n != rep->length); if (rep->tag == SUBSTRING) { CordRepSubstring* substring = rep->substring(); offset += substring->start; rep = CordRep::Ref(substring->child); CordRep::Unref(substring); } assert(rep->IsExternal() || rep->IsFlat()); CordRepSubstring* substring = new CordRepSubstring(); substring->length = n; substring->tag = SUBSTRING; substring->start = offset; substring->child = rep; return substring; } // TODO(b/192061034): consider making this a cord rep library function. inline CordRep* MakeSubstring(CordRep* rep, size_t offset, size_t n) { if (n == rep->length) return rep; if (n == 0) return CordRep::Unref(rep), nullptr; return CreateSubstring(rep, offset, n); } // TODO(b/192061034): consider making this a cord rep library function. inline CordRep* MakeSubstring(CordRep* rep, size_t offset) { if (offset == 0) return rep; return CreateSubstring(rep, offset, rep->length - offset); } // Resizes `edge` to the provided `length`. Adopts a reference on `edge`. // This method directly returns `edge` if `length` equals `edge->length`. // If `is_mutable` is set to true, this function may return `edge` with // `edge->length` set to the new length depending on the type and size of // `edge`. Otherwise, this function returns a new CordRepSubstring value. // Requires `length > 0 && length <= edge->length`. CordRep* ResizeEdge(CordRep* edge, size_t length, bool is_mutable) { assert(length > 0); assert(length <= edge->length); assert(IsDataEdge(edge)); if (length >= edge->length) return edge; if (is_mutable && (edge->tag >= FLAT || edge->tag == SUBSTRING)) { edge->length = length; return edge; } return CreateSubstring(edge, 0, length); } template inline absl::string_view Consume(absl::string_view s, size_t n) { return edge_type == kBack ? s.substr(n) : s.substr(0, s.size() - n); } template inline absl::string_view Consume(char* dst, absl::string_view s, size_t n) { if (edge_type == kBack) { memcpy(dst, s.data(), n); return s.substr(n); } else { const size_t offset = s.size() - n; memcpy(dst, s.data() + offset, n); return s.substr(0, offset); } } // Known issue / optimization weirdness: the store associated with the // decrement introduces traffic between cpus (even if the result of that // traffic does nothing), making this faster than a single call to // refcount.Decrement() checking the zero refcount condition. template inline void FastUnref(R* r, Fn&& fn) { if (r->refcount.IsOne()) { fn(r); } else if (!r->refcount.DecrementExpectHighRefcount()) { fn(r); } } void DeleteSubstring(CordRepSubstring* substring) { CordRep* rep = substring->child; if (!rep->refcount.Decrement()) { if (rep->tag >= FLAT) { CordRepFlat::Delete(rep->flat()); } else { assert(rep->tag == EXTERNAL); CordRepExternal::Delete(rep->external()); } } delete substring; } // Deletes a leaf node data edge. Requires `IsDataEdge(rep)`. void DeleteLeafEdge(CordRep* rep) { assert(IsDataEdge(rep)); if (rep->tag >= FLAT) { CordRepFlat::Delete(rep->flat()); } else if (rep->tag == EXTERNAL) { CordRepExternal::Delete(rep->external()); } else { DeleteSubstring(rep->substring()); } } // StackOperations contains the logic to build a left-most or right-most stack // (leg) down to the leaf level of a btree, and 'unwind' / 'Finalize' methods to // propagate node changes up the stack. template struct StackOperations { // Returns true if the node at 'depth' is not shared, i.e. has a refcount // of one and all of its parent nodes have a refcount of one. inline bool owned(int depth) const { return depth < share_depth; } // Returns the node at 'depth'. inline CordRepBtree* node(int depth) const { return stack[depth]; } // Builds a `depth` levels deep stack starting at `tree` recording which nodes // are private in the form of the 'share depth' where nodes are shared. inline CordRepBtree* BuildStack(CordRepBtree* tree, int depth) { assert(depth <= tree->height()); int current_depth = 0; while (current_depth < depth && tree->refcount.IsOne()) { stack[current_depth++] = tree; tree = tree->Edge(edge_type)->btree(); } share_depth = current_depth + (tree->refcount.IsOne() ? 1 : 0); while (current_depth < depth) { stack[current_depth++] = tree; tree = tree->Edge(edge_type)->btree(); } return tree; } // Builds a stack with the invariant that all nodes are private owned / not // shared. This is used in iterative updates where a previous propagation // guaranteed all nodes are owned / private. inline void BuildOwnedStack(CordRepBtree* tree, int height) { assert(height <= CordRepBtree::kMaxHeight); int depth = 0; while (depth < height) { assert(tree->refcount.IsOne()); stack[depth++] = tree; tree = tree->Edge(edge_type)->btree(); } assert(tree->refcount.IsOne()); share_depth = depth + 1; } // Processes the final 'top level' result action for the tree. // See the 'Action' enum for the various action implications. static inline CordRepBtree* Finalize(CordRepBtree* tree, OpResult result) { switch (result.action) { case CordRepBtree::kPopped: tree = edge_type == kBack ? CordRepBtree::New(tree, result.tree) : CordRepBtree::New(result.tree, tree); if (ABSL_PREDICT_FALSE(tree->height() > CordRepBtree::kMaxHeight)) { tree = CordRepBtree::Rebuild(tree); ABSL_RAW_CHECK(tree->height() <= CordRepBtree::kMaxHeight, "Max height exceeded"); } return tree; case CordRepBtree::kCopied: CordRep::Unref(tree); ABSL_FALLTHROUGH_INTENDED; case CordRepBtree::kSelf: return result.tree; } ABSL_UNREACHABLE(); return result.tree; } // Propagate the action result in 'result' up into all nodes of the stack // starting at depth 'depth'. 'length' contains the extra length of data that // was added at the lowest level, and is updated into all nodes of the stack. // See the 'Action' enum for the various action implications. // If 'propagate' is true, then any copied node values are updated into the // stack, which is used for iterative processing on the same stack. template inline CordRepBtree* Unwind(CordRepBtree* tree, int depth, size_t length, OpResult result) { // TODO(mvels): revisit the below code to check if 3 loops with 3 // (incremental) conditions is faster than 1 loop with a switch. // Benchmarking and perf recordings indicate the loop with switch is // fastest, likely because of indirect jumps on the tight case values and // dense branches. But it's worth considering 3 loops, as the `action` // transitions are mono directional. E.g.: // while (action == kPopped) { // ... // } // while (action == kCopied) { // ... // } // ... // We also found that an "if () do {}" loop here seems faster, possibly // because it allows the branch predictor more granular heuristics on // 'single leaf' (`depth` == 0) and 'single depth' (`depth` == 1) cases // which appear to be the most common use cases. if (depth != 0) { do { CordRepBtree* node = stack[--depth]; const bool owned = depth < share_depth; switch (result.action) { case CordRepBtree::kPopped: assert(!propagate); result = node->AddEdge(owned, result.tree, length); break; case CordRepBtree::kCopied: result = node->SetEdge(owned, result.tree, length); if (propagate) stack[depth] = result.tree; break; case CordRepBtree::kSelf: node->length += length; while (depth > 0) { node = stack[--depth]; node->length += length; } return node; } } while (depth > 0); } return Finalize(tree, result); } // Invokes `Unwind` with `propagate=true` to update the stack node values. inline CordRepBtree* Propagate(CordRepBtree* tree, int depth, size_t length, OpResult result) { return Unwind(tree, depth, length, result); } // `share_depth` contains the depth at which the nodes in the stack become // shared. I.e., if the top most level is shared (i.e.: `!refcount.IsOne()`), // then `share_depth` is 0. If the 2nd node is shared (and implicitly all // nodes below that) then `share_depth` is 1, etc. A `share_depth` greater // than the depth of the stack indicates that none of the nodes in the stack // are shared. int share_depth; NodeStack stack; }; } // namespace void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation) { cord_btree_exhaustive_validation.store(do_exaustive_validation, std::memory_order_relaxed); } bool IsCordBtreeExhaustiveValidationEnabled() { return cord_btree_exhaustive_validation.load(std::memory_order_relaxed); } void CordRepBtree::Dump(const CordRep* rep, absl::string_view label, bool include_contents, std::ostream& stream) { stream << "===================================\n"; if (!label.empty()) { stream << label << '\n'; stream << "-----------------------------------\n"; } if (rep) { DumpAll(rep, include_contents, stream); } else { stream << "NULL\n"; } } void CordRepBtree::Dump(const CordRep* rep, absl::string_view label, std::ostream& stream) { Dump(rep, label, false, stream); } void CordRepBtree::Dump(const CordRep* rep, std::ostream& stream) { Dump(rep, absl::string_view(), false, stream); } template static void DestroyTree(CordRepBtree* tree) { for (CordRep* node : tree->Edges()) { if (node->refcount.Decrement()) continue; for (CordRep* edge : node->btree()->Edges()) { if (edge->refcount.Decrement()) continue; if (size == 1) { DeleteLeafEdge(edge); } else { CordRepBtree::Destroy(edge->btree()); } } CordRepBtree::Delete(node->btree()); } CordRepBtree::Delete(tree); } void CordRepBtree::Destroy(CordRepBtree* tree) { switch (tree->height()) { case 0: for (CordRep* edge : tree->Edges()) { if (!edge->refcount.Decrement()) { DeleteLeafEdge(edge); } } return CordRepBtree::Delete(tree); case 1: return DestroyTree<1>(tree); default: return DestroyTree<2>(tree); } } bool CordRepBtree::IsValid(const CordRepBtree* tree, bool shallow) { #define NODE_CHECK_VALID(x) \ if (!(x)) { \ ABSL_RAW_LOG(ERROR, "CordRepBtree::CheckValid() FAILED: %s", #x); \ return false; \ } #define NODE_CHECK_EQ(x, y) \ if ((x) != (y)) { \ ABSL_RAW_LOG(ERROR, \ "CordRepBtree::CheckValid() FAILED: %s != %s (%s vs %s)", #x, \ #y, absl::StrCat(x).c_str(), absl::StrCat(y).c_str()); \ return false; \ } NODE_CHECK_VALID(tree != nullptr); NODE_CHECK_VALID(tree->IsBtree()); NODE_CHECK_VALID(tree->height() <= kMaxHeight); NODE_CHECK_VALID(tree->begin() < tree->capacity()); NODE_CHECK_VALID(tree->end() <= tree->capacity()); NODE_CHECK_VALID(tree->begin() <= tree->end()); size_t child_length = 0; for (CordRep* edge : tree->Edges()) { NODE_CHECK_VALID(edge != nullptr); if (tree->height() > 0) { NODE_CHECK_VALID(edge->IsBtree()); NODE_CHECK_VALID(edge->btree()->height() == tree->height() - 1); } else { NODE_CHECK_VALID(IsDataEdge(edge)); } child_length += edge->length; } NODE_CHECK_EQ(child_length, tree->length); if ((!shallow || IsCordBtreeExhaustiveValidationEnabled()) && tree->height() > 0) { for (CordRep* edge : tree->Edges()) { if (!IsValid(edge->btree(), shallow)) return false; } } return true; #undef NODE_CHECK_VALID #undef NODE_CHECK_EQ } #ifndef NDEBUG CordRepBtree* CordRepBtree::AssertValid(CordRepBtree* tree, bool shallow) { if (!IsValid(tree, shallow)) { Dump(tree, "CordRepBtree validation failed:", false, std::cout); ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED"); } return tree; } const CordRepBtree* CordRepBtree::AssertValid(const CordRepBtree* tree, bool shallow) { if (!IsValid(tree, shallow)) { Dump(tree, "CordRepBtree validation failed:", false, std::cout); ABSL_RAW_LOG(FATAL, "CordRepBtree::CheckValid() FAILED"); } return tree; } #endif // NDEBUG template inline OpResult CordRepBtree::AddEdge(bool owned, CordRep* edge, size_t delta) { if (size() >= kMaxCapacity) return {New(edge), kPopped}; OpResult result = ToOpResult(owned); result.tree->Add(edge); result.tree->length += delta; return result; } template OpResult CordRepBtree::SetEdge(bool owned, CordRep* edge, size_t delta) { OpResult result; const size_t idx = index(edge_type); if (owned) { result = {this, kSelf}; CordRep::Unref(edges_[idx]); } else { // Create a copy containing all unchanged edges. Unchanged edges are the // open interval [begin, back) or [begin + 1, end) depending on `edge_type`. // We conveniently cover both case using a constexpr `shift` being 0 or 1 // as `end :== back + 1`. result = {CopyRaw(length), kCopied}; constexpr int shift = edge_type == kFront ? 1 : 0; for (CordRep* r : Edges(begin() + shift, back() + shift)) { CordRep::Ref(r); } } result.tree->edges_[idx] = edge; result.tree->length += delta; return result; } template CordRepBtree* CordRepBtree::AddCordRep(CordRepBtree* tree, CordRep* rep) { const int depth = tree->height(); const size_t length = rep->length; StackOperations ops; CordRepBtree* leaf = ops.BuildStack(tree, depth); const OpResult result = leaf->AddEdge(ops.owned(depth), rep, length); return ops.Unwind(tree, depth, length, result); } template <> CordRepBtree* CordRepBtree::NewLeaf(absl::string_view data, size_t extra) { CordRepBtree* leaf = CordRepBtree::New(0); size_t length = 0; size_t end = 0; const size_t cap = leaf->capacity(); while (!data.empty() && end != cap) { auto* flat = CordRepFlat::New(data.length() + extra); flat->length = (std::min)(data.length(), flat->Capacity()); length += flat->length; leaf->edges_[end++] = flat; data = Consume(flat->Data(), data, flat->length); } leaf->length = length; leaf->set_end(end); return leaf; } template <> CordRepBtree* CordRepBtree::NewLeaf(absl::string_view data, size_t extra) { CordRepBtree* leaf = CordRepBtree::New(0); size_t length = 0; size_t begin = leaf->capacity(); leaf->set_end(leaf->capacity()); while (!data.empty() && begin != 0) { auto* flat = CordRepFlat::New(data.length() + extra); flat->length = (std::min)(data.length(), flat->Capacity()); length += flat->length; leaf->edges_[--begin] = flat; data = Consume(flat->Data(), data, flat->length); } leaf->length = length; leaf->set_begin(begin); return leaf; } template <> absl::string_view CordRepBtree::AddData(absl::string_view data, size_t extra) { assert(!data.empty()); assert(size() < capacity()); AlignBegin(); const size_t cap = capacity(); do { CordRepFlat* flat = CordRepFlat::New(data.length() + extra); const size_t n = (std::min)(data.length(), flat->Capacity()); flat->length = n; edges_[fetch_add_end(1)] = flat; data = Consume(flat->Data(), data, n); } while (!data.empty() && end() != cap); return data; } template <> absl::string_view CordRepBtree::AddData(absl::string_view data, size_t extra) { assert(!data.empty()); assert(size() < capacity()); AlignEnd(); do { CordRepFlat* flat = CordRepFlat::New(data.length() + extra); const size_t n = (std::min)(data.length(), flat->Capacity()); flat->length = n; edges_[sub_fetch_begin(1)] = flat; data = Consume(flat->Data(), data, n); } while (!data.empty() && begin() != 0); return data; } template CordRepBtree* CordRepBtree::AddData(CordRepBtree* tree, absl::string_view data, size_t extra) { if (ABSL_PREDICT_FALSE(data.empty())) return tree; const size_t original_data_size = data.size(); int depth = tree->height(); StackOperations ops; CordRepBtree* leaf = ops.BuildStack(tree, depth); // If there is capacity in the last edge, append as much data // as possible into this last edge. if (leaf->size() < leaf->capacity()) { OpResult result = leaf->ToOpResult(ops.owned(depth)); data = result.tree->AddData(data, extra); if (data.empty()) { result.tree->length += original_data_size; return ops.Unwind(tree, depth, original_data_size, result); } // We added some data into this leaf, but not all. Propagate the added // length to the top most node, and rebuild the stack with any newly copied // or updated nodes. From this point on, the path (leg) from the top most // node to the right-most node towards the leaf node is privately owned. size_t delta = original_data_size - data.size(); assert(delta > 0); result.tree->length += delta; tree = ops.Propagate(tree, depth, delta, result); ops.share_depth = depth + 1; } // We were unable to append all data into the existing right-most leaf node. // This means all remaining data must be put into (a) new leaf node(s) which // we append to the tree. To make this efficient, we iteratively build full // leaf nodes from `data` until the created leaf contains all remaining data. // We utilize the `Unwind` method to merge the created leaf into the first // level towards root that has capacity. On each iteration with remaining // data, we rebuild the stack in the knowledge that right-most nodes are // privately owned after the first `Unwind` completes. for (;;) { OpResult result = {CordRepBtree::NewLeaf(data, extra), kPopped}; if (result.tree->length == data.size()) { return ops.Unwind(tree, depth, result.tree->length, result); } data = Consume(data, result.tree->length); tree = ops.Unwind(tree, depth, result.tree->length, result); depth = tree->height(); ops.BuildOwnedStack(tree, depth); } } template CordRepBtree* CordRepBtree::Merge(CordRepBtree* dst, CordRepBtree* src) { assert(dst->height() >= src->height()); // Capture source length as we may consume / destroy `src`. const size_t length = src->length; // We attempt to merge `src` at its corresponding height in `dst`. const int depth = dst->height() - src->height(); StackOperations ops; CordRepBtree* merge_node = ops.BuildStack(dst, depth); // If there is enough space in `merge_node` for all edges from `src`, add all // edges to this node, making a fresh copy as needed if not privately owned. // If `merge_node` does not have capacity for `src`, we rely on `Unwind` and // `Finalize` to merge `src` into the first level towards `root` where there // is capacity for another edge, or create a new top level node. OpResult result; if (merge_node->size() + src->size() <= kMaxCapacity) { result = merge_node->ToOpResult(ops.owned(depth)); result.tree->Add(src->Edges()); result.tree->length += src->length; if (src->refcount.IsOne()) { Delete(src); } else { for (CordRep* edge : src->Edges()) CordRep::Ref(edge); CordRepBtree::Unref(src); } } else { result = {src, kPopped}; } // Unless we merged at the top level (i.e.: src and dst are equal height), // unwind the result towards the top level, and finalize the result. if (depth) { return ops.Unwind(dst, depth, length, result); } return ops.Finalize(dst, result); } CopyResult CordRepBtree::CopySuffix(size_t offset) { assert(offset < this->length); // As long as `offset` starts inside the last edge, we can 'drop' the current // depth. For the most extreme example: if offset references the last data // edge in the tree, there is only a single edge / path from the top of the // tree to that last edge, so we can drop all the nodes except that edge. // The fast path check for this is `back->length >= length - offset`. int height = this->height(); CordRepBtree* node = this; size_t len = node->length - offset; CordRep* back = node->Edge(kBack); while (back->length >= len) { offset = back->length - len; if (--height < 0) { return {MakeSubstring(CordRep::Ref(back), offset), height}; } node = back->btree(); back = node->Edge(kBack); } if (offset == 0) return {CordRep::Ref(node), height}; // Offset does not point into the last edge, so we span at least two edges. // Find the index of offset with `IndexBeyond` which provides us the edge // 'beyond' the offset if offset is not a clean starting point of an edge. Position pos = node->IndexBeyond(offset); CordRepBtree* sub = node->CopyToEndFrom(pos.index, len); const CopyResult result = {sub, height}; // `pos.n` contains a non zero value if the offset is not an exact starting // point of an edge. In this case, `pos.n` contains the 'trailing' amount of // bytes of the edge preceding that in `pos.index`. We need to iteratively // adjust the preceding edge with the 'broken' offset until we have a perfect // start of the edge. while (pos.n != 0) { assert(pos.index >= 1); const size_t begin = pos.index - 1; sub->set_begin(begin); CordRep* const edge = node->Edge(begin); len = pos.n; offset = edge->length - len; if (--height < 0) { sub->edges_[begin] = MakeSubstring(CordRep::Ref(edge), offset, len); return result; } node = edge->btree(); pos = node->IndexBeyond(offset); CordRepBtree* nsub = node->CopyToEndFrom(pos.index, len); sub->edges_[begin] = nsub; sub = nsub; } sub->set_begin(pos.index); return result; } CopyResult CordRepBtree::CopyPrefix(size_t n, bool allow_folding) { assert(n > 0); assert(n <= this->length); // As long as `n` does not exceed the length of the first edge, we can 'drop' // the current depth. For the most extreme example: if we'd copy a 1 byte // prefix from a tree, there is only a single edge / path from the top of the // tree to the single data edge containing this byte, so we can drop all the // nodes except the data node. int height = this->height(); CordRepBtree* node = this; CordRep* front = node->Edge(kFront); if (allow_folding) { while (front->length >= n) { if (--height < 0) return {MakeSubstring(CordRep::Ref(front), 0, n), -1}; node = front->btree(); front = node->Edge(kFront); } } if (node->length == n) return {CordRep::Ref(node), height}; // `n` spans at least two nodes, find the end point of the span. Position pos = node->IndexOf(n); // Create a partial copy of the node up to `pos.index`, with a defined length // of `n`. Any 'partial last edge' is added further below as needed. CordRepBtree* sub = node->CopyBeginTo(pos.index, n); const CopyResult result = {sub, height}; // `pos.n` contains the 'offset inside the edge for IndexOf(n)'. As long as // this is not zero, we don't have a 'clean cut', so we need to make a // (partial) copy of that last edge, and repeat this until pos.n is zero. while (pos.n != 0) { size_t end = pos.index; n = pos.n; CordRep* edge = node->Edge(pos.index); if (--height < 0) { sub->edges_[end++] = MakeSubstring(CordRep::Ref(edge), 0, n); sub->set_end(end); AssertValid(result.edge->btree()); return result; } node = edge->btree(); pos = node->IndexOf(n); CordRepBtree* nsub = node->CopyBeginTo(pos.index, n); sub->edges_[end++] = nsub; sub->set_end(end); sub = nsub; } sub->set_end(pos.index); AssertValid(result.edge->btree()); return result; } CordRep* CordRepBtree::ExtractFront(CordRepBtree* tree) { CordRep* front = tree->Edge(tree->begin()); if (tree->refcount.IsOne()) { Unref(tree->Edges(tree->begin() + 1, tree->end())); CordRepBtree::Delete(tree); } else { CordRep::Ref(front); CordRep::Unref(tree); } return front; } CordRepBtree* CordRepBtree::ConsumeBeginTo(CordRepBtree* tree, size_t end, size_t new_length) { assert(end <= tree->end()); if (tree->refcount.IsOne()) { Unref(tree->Edges(end, tree->end())); tree->set_end(end); tree->length = new_length; } else { CordRepBtree* old = tree; tree = tree->CopyBeginTo(end, new_length); CordRep::Unref(old); } return tree; } CordRep* CordRepBtree::RemoveSuffix(CordRepBtree* tree, size_t n) { // Check input and deal with trivial cases 'Remove all/none' assert(tree != nullptr); assert(n <= tree->length); const size_t len = tree->length; if (ABSL_PREDICT_FALSE(n == 0)) { return tree; } if (ABSL_PREDICT_FALSE(n >= len)) { CordRepBtree::Unref(tree); return nullptr; } size_t length = len - n; int height = tree->height(); bool is_mutable = tree->refcount.IsOne(); // Extract all top nodes which are reduced to size = 1 Position pos = tree->IndexOfLength(length); while (pos.index == tree->begin()) { CordRep* edge = ExtractFront(tree); is_mutable &= edge->refcount.IsOne(); if (height-- == 0) return ResizeEdge(edge, length, is_mutable); tree = edge->btree(); pos = tree->IndexOfLength(length); } // Repeat the following sequence traversing down the tree: // - Crop the top node to the 'last remaining edge' adjusting length. // - Set the length for down edges to the partial length in that last edge. // - Repeat this until the last edge is 'included in full' // - If we hit the data edge level, resize and return the last data edge CordRepBtree* top = tree = ConsumeBeginTo(tree, pos.index + 1, length); CordRep* edge = tree->Edge(pos.index); length = pos.n; while (length != edge->length) { // ConsumeBeginTo guarantees `tree` is a clean, privately owned copy. assert(tree->refcount.IsOne()); const bool edge_is_mutable = edge->refcount.IsOne(); if (height-- == 0) { tree->edges_[pos.index] = ResizeEdge(edge, length, edge_is_mutable); return AssertValid(top); } if (!edge_is_mutable) { // We can't 'in place' remove any suffixes down this edge. // Replace this edge with a prefix copy instead. tree->edges_[pos.index] = edge->btree()->CopyPrefix(length, false).edge; CordRep::Unref(edge); return AssertValid(top); } // Move down one level, rinse repeat. tree = edge->btree(); pos = tree->IndexOfLength(length); tree = ConsumeBeginTo(edge->btree(), pos.index + 1, length); edge = tree->Edge(pos.index); length = pos.n; } return AssertValid(top); } CordRep* CordRepBtree::SubTree(size_t offset, size_t n) { assert(n <= this->length); assert(offset <= this->length - n); if (ABSL_PREDICT_FALSE(n == 0)) return nullptr; CordRepBtree* node = this; int height = node->height(); Position front = node->IndexOf(offset); CordRep* left = node->edges_[front.index]; while (front.n + n <= left->length) { if (--height < 0) return MakeSubstring(CordRep::Ref(left), front.n, n); node = left->btree(); front = node->IndexOf(front.n); left = node->edges_[front.index]; } const Position back = node->IndexBefore(front, n); CordRep* const right = node->edges_[back.index]; assert(back.index > front.index); // Get partial suffix and prefix entries. CopyResult prefix; CopyResult suffix; if (height > 0) { // Copy prefix and suffix of the boundary nodes. prefix = left->btree()->CopySuffix(front.n); suffix = right->btree()->CopyPrefix(back.n); // If there is an edge between the prefix and suffix edges, then the tree // must remain at its previous (full) height. If we have no edges between // prefix and suffix edges, then the tree must be as high as either the // suffix or prefix edges (which are collapsed to their minimum heights). if (front.index + 1 == back.index) { height = (std::max)(prefix.height, suffix.height) + 1; } // Raise prefix and suffixes to the new tree height. for (int h = prefix.height + 1; h < height; ++h) { prefix.edge = CordRepBtree::New(prefix.edge); } for (int h = suffix.height + 1; h < height; ++h) { suffix.edge = CordRepBtree::New(suffix.edge); } } else { // Leaf node, simply take substrings for prefix and suffix. prefix = CopyResult{MakeSubstring(CordRep::Ref(left), front.n), -1}; suffix = CopyResult{MakeSubstring(CordRep::Ref(right), 0, back.n), -1}; } // Compose resulting tree. CordRepBtree* sub = CordRepBtree::New(height); size_t end = 0; sub->edges_[end++] = prefix.edge; for (CordRep* r : node->Edges(front.index + 1, back.index)) { sub->edges_[end++] = CordRep::Ref(r); } sub->edges_[end++] = suffix.edge; sub->set_end(end); sub->length = n; return AssertValid(sub); } CordRepBtree* CordRepBtree::MergeTrees(CordRepBtree* left, CordRepBtree* right) { return left->height() >= right->height() ? Merge(left, right) : Merge(right, left); } bool CordRepBtree::IsFlat(absl::string_view* fragment) const { if (height() == 0 && size() == 1) { if (fragment) *fragment = Data(begin()); return true; } return false; } bool CordRepBtree::IsFlat(size_t offset, const size_t n, absl::string_view* fragment) const { assert(n <= this->length); assert(offset <= this->length - n); if (ABSL_PREDICT_FALSE(n == 0)) return false; int height = this->height(); const CordRepBtree* node = this; for (;;) { const Position front = node->IndexOf(offset); const CordRep* edge = node->Edge(front.index); if (edge->length < front.n + n) return false; if (--height < 0) { if (fragment) *fragment = EdgeData(edge).substr(front.n, n); return true; } offset = front.n; node = node->Edge(front.index)->btree(); } } char CordRepBtree::GetCharacter(size_t offset) const { assert(offset < length); const CordRepBtree* node = this; int height = node->height(); for (;;) { Position front = node->IndexOf(offset); if (--height < 0) return node->Data(front.index)[front.n]; offset = front.n; node = node->Edge(front.index)->btree(); } } Span CordRepBtree::GetAppendBufferSlow(size_t size) { // The inlined version in `GetAppendBuffer()` deals with all heights <= 3. assert(height() >= 4); assert(refcount.IsOne()); // Build a stack of nodes we may potentially need to update if we find a // non-shared FLAT with capacity at the leaf level. const int depth = height(); CordRepBtree* node = this; CordRepBtree* stack[kMaxDepth]; for (int i = 0; i < depth; ++i) { node = node->Edge(kBack)->btree(); if (!node->refcount.IsOne()) return {}; stack[i] = node; } // Must be a privately owned, mutable flat. CordRep* const edge = node->Edge(kBack); if (!edge->refcount.IsOne() || edge->tag < FLAT) return {}; // Must have capacity. const size_t avail = edge->flat()->Capacity() - edge->length; if (avail == 0) return {}; // Build span on remaining capacity. size_t delta = (std::min)(size, avail); Span span = {edge->flat()->Data() + edge->length, delta}; edge->length += delta; this->length += delta; for (int i = 0; i < depth; ++i) { stack[i]->length += delta; } return span; } CordRepBtree* CordRepBtree::CreateSlow(CordRep* rep) { if (rep->IsBtree()) return rep->btree(); CordRepBtree* node = nullptr; auto consume = [&node](CordRep* r, size_t offset, size_t length) { r = MakeSubstring(r, offset, length); if (node == nullptr) { node = New(r); } else { node = CordRepBtree::AddCordRep(node, r); } }; Consume(rep, consume); return node; } CordRepBtree* CordRepBtree::AppendSlow(CordRepBtree* tree, CordRep* rep) { if (ABSL_PREDICT_TRUE(rep->IsBtree())) { return MergeTrees(tree, rep->btree()); } auto consume = [&tree](CordRep* r, size_t offset, size_t length) { r = MakeSubstring(r, offset, length); tree = CordRepBtree::AddCordRep(tree, r); }; Consume(rep, consume); return tree; } CordRepBtree* CordRepBtree::PrependSlow(CordRepBtree* tree, CordRep* rep) { if (ABSL_PREDICT_TRUE(rep->IsBtree())) { return MergeTrees(rep->btree(), tree); } auto consume = [&tree](CordRep* r, size_t offset, size_t length) { r = MakeSubstring(r, offset, length); tree = CordRepBtree::AddCordRep(tree, r); }; ReverseConsume(rep, consume); return tree; } CordRepBtree* CordRepBtree::Append(CordRepBtree* tree, absl::string_view data, size_t extra) { return CordRepBtree::AddData(tree, data, extra); } CordRepBtree* CordRepBtree::Prepend(CordRepBtree* tree, absl::string_view data, size_t extra) { return CordRepBtree::AddData(tree, data, extra); } template CordRepBtree* CordRepBtree::AddCordRep(CordRepBtree* tree, CordRep* rep); template CordRepBtree* CordRepBtree::AddCordRep(CordRepBtree* tree, CordRep* rep); template CordRepBtree* CordRepBtree::AddData(CordRepBtree* tree, absl::string_view data, size_t extra); template CordRepBtree* CordRepBtree::AddData(CordRepBtree* tree, absl::string_view data, size_t extra); void CordRepBtree::Rebuild(CordRepBtree** stack, CordRepBtree* tree, bool consume) { bool owned = consume && tree->refcount.IsOne(); if (tree->height() == 0) { for (CordRep* edge : tree->Edges()) { if (!owned) edge = CordRep::Ref(edge); size_t height = 0; size_t length = edge->length; CordRepBtree* node = stack[0]; OpResult result = node->AddEdge(true, edge, length); while (result.action == CordRepBtree::kPopped) { stack[height] = result.tree; if (stack[++height] == nullptr) { result.action = CordRepBtree::kSelf; stack[height] = CordRepBtree::New(node, result.tree); } else { node = stack[height]; result = node->AddEdge(true, result.tree, length); } } while (stack[++height] != nullptr) { stack[height]->length += length; } } } else { for (CordRep* rep : tree->Edges()) { Rebuild(stack, rep->btree(), owned); } } if (consume) { if (owned) { CordRepBtree::Delete(tree); } else { CordRepBtree::Unref(tree); } } } CordRepBtree* CordRepBtree::Rebuild(CordRepBtree* tree) { // Set up initial stack with empty leaf node. CordRepBtree* node = CordRepBtree::New(); CordRepBtree* stack[CordRepBtree::kMaxDepth + 1] = {node}; // Recursively build the tree, consuming the input tree. Rebuild(stack, tree, /* consume reference */ true); // Return top most node for (CordRepBtree* parent : stack) { if (parent == nullptr) return node; node = parent; } // Unreachable assert(false); return nullptr; } CordRepBtree::ExtractResult CordRepBtree::ExtractAppendBuffer( CordRepBtree* tree, size_t extra_capacity) { int depth = 0; NodeStack stack; // Set up default 'no success' result which is {tree, nullptr}. ExtractResult result; result.tree = tree; result.extracted = nullptr; // Dive down the right side of the tree, making sure no edges are shared. while (tree->height() > 0) { if (!tree->refcount.IsOne()) return result; stack[depth++] = tree; tree = tree->Edge(kBack)->btree(); } if (!tree->refcount.IsOne()) return result; // Validate we ended on a non shared flat. CordRep* rep = tree->Edge(kBack); if (!(rep->IsFlat() && rep->refcount.IsOne())) return result; // Verify it has at least the requested extra capacity. CordRepFlat* flat = rep->flat(); const size_t length = flat->length; const size_t avail = flat->Capacity() - flat->length; if (extra_capacity > avail) return result; // Set the extracted flat in the result. result.extracted = flat; // Cascading delete all nodes that become empty. while (tree->size() == 1) { CordRepBtree::Delete(tree); if (--depth < 0) { // We consumed the entire tree: return nullptr for new tree. result.tree = nullptr; return result; } rep = tree; tree = stack[depth]; } // Remove the edge or cascaded up parent node. tree->set_end(tree->end() - 1); tree->length -= length; // Adjust lengths up the tree. while (depth > 0) { tree = stack[--depth]; tree->length -= length; } // Remove unnecessary top nodes with size = 1. This may iterate all the way // down to the leaf node in which case we simply return the remaining last // edge in that node and the extracted flat. while (tree->size() == 1) { int height = tree->height(); rep = tree->Edge(kBack); Delete(tree); if (height == 0) { // We consumed the leaf: return the sole data edge as the new tree. result.tree = rep; return result; } tree = rep->btree(); } // Done: return the (new) top level node and extracted flat. result.tree = tree; return result; } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl s2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_statistics.h0000644000175000017510000000657314737212474025425 0ustar nileshnilesh// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ #include #include "absl/base/config.h" #include "absl/strings/internal/cordz_update_tracker.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // CordzStatistics captures some meta information about a Cord's shape. struct CordzStatistics { using MethodIdentifier = CordzUpdateTracker::MethodIdentifier; // Node counts information struct NodeCounts { size_t flat = 0; // #flats size_t flat_64 = 0; // #flats up to 64 bytes size_t flat_128 = 0; // #flats up to 128 bytes size_t flat_256 = 0; // #flats up to 256 bytes size_t flat_512 = 0; // #flats up to 512 bytes size_t flat_1k = 0; // #flats up to 1K bytes size_t external = 0; // #external reps size_t substring = 0; // #substring reps size_t concat = 0; // #concat reps size_t ring = 0; // #ring buffer reps size_t btree = 0; // #btree reps size_t crc = 0; // #crc reps }; // The size of the cord in bytes. This matches the result of Cord::size(). size_t size = 0; // The estimated memory used by the sampled cord. This value matches the // value as reported by Cord::EstimatedMemoryUsage(). // A value of 0 implies the property has not been recorded. size_t estimated_memory_usage = 0; // The effective memory used by the sampled cord, inversely weighted by the // effective indegree of each allocated node. This is a representation of the // fair share of memory usage that should be attributed to the sampled cord. // This value is more useful for cases where one or more nodes are referenced // by multiple Cord instances, and for cases where a Cord includes the same // node multiple times (either directly or indirectly). // A value of 0 implies the property has not been recorded. size_t estimated_fair_share_memory_usage = 0; // The total number of nodes referenced by this cord. // For ring buffer Cords, this includes the 'ring buffer' node. // For btree Cords, this includes all 'CordRepBtree' tree nodes as well as all // the substring, flat and external nodes referenced by the tree. // A value of 0 implies the property has not been recorded. size_t node_count = 0; // Detailed node counts per type NodeCounts node_counts; // The cord method responsible for sampling the cord. MethodIdentifier method = MethodIdentifier::kUnknown; // The cord method responsible for sampling the parent cord if applicable. MethodIdentifier parent_method = MethodIdentifier::kUnknown; // Update tracker tracking invocation count per cord method. CordzUpdateTracker update_tracker; }; } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_STATISTICS_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cord_rep_btree_navigator.h0000644000175000017510000002367514737212474027064 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ #define ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ #include #include #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // CordRepBtreeNavigator is a bi-directional navigator allowing callers to // navigate all the (leaf) data edges in a CordRepBtree instance. // // A CordRepBtreeNavigator instance is by default empty. Callers initialize a // navigator instance by calling one of `InitFirst()`, `InitLast()` or // `InitOffset()`, which establishes a current position. Callers can then // navigate using the `Next`, `Previous`, `Skip` and `Seek` methods. // // The navigator instance does not take or adopt a reference on the provided // `tree` on any of the initialization calls. Callers are responsible for // guaranteeing the lifecycle of the provided tree. A navigator instance can // be reset to the empty state by calling `Reset`. // // A navigator only keeps positional state on the 'current data edge', it does // explicitly not keep any 'offset' state. The class does accept and return // offsets in the `Read()`, `Skip()` and 'Seek()` methods as these would // otherwise put a big burden on callers. Callers are expected to maintain // (returned) offset info if they require such granular state. class CordRepBtreeNavigator { public: // The logical position as returned by the Seek() and Skip() functions. // Returns the current leaf edge for the desired seek or skip position and // the offset of that position inside that edge. struct Position { CordRep* edge; size_t offset; }; // The read result as returned by the Read() function. // `tree` contains the resulting tree which is identical to the result // of calling CordRepBtree::SubTree(...) on the tree being navigated. // `n` contains the number of bytes used from the last navigated to // edge of the tree. struct ReadResult { CordRep* tree; size_t n; }; // Returns true if this instance is not empty. explicit operator bool() const; // Returns the tree for this instance or nullptr if empty. CordRepBtree* btree() const; // Returns the data edge of the current position. // Requires this instance to not be empty. CordRep* Current() const; // Resets this navigator to `tree`, returning the first data edge in the tree. CordRep* InitFirst(CordRepBtree* tree); // Resets this navigator to `tree`, returning the last data edge in the tree. CordRep* InitLast(CordRepBtree* tree); // Resets this navigator to `tree` returning the data edge at position // `offset` and the relative offset of `offset` into that data edge. // Returns `Position.edge = nullptr` if the provided offset is greater // than or equal to the length of the tree, in which case the state of // the navigator instance remains unchanged. Position InitOffset(CordRepBtree* tree, size_t offset); // Navigates to the next data edge. // Returns the next data edge or nullptr if there is no next data edge, in // which case the current position remains unchanged. CordRep* Next(); // Navigates to the previous data edge. // Returns the previous data edge or nullptr if there is no previous data // edge, in which case the current position remains unchanged. CordRep* Previous(); // Navigates to the data edge at position `offset`. Returns the navigated to // data edge in `Position.edge` and the relative offset of `offset` into that // data edge in `Position.offset`. Returns `Position.edge = nullptr` if the // provide offset is greater than or equal to the tree's length. Position Seek(size_t offset); // Reads `n` bytes of data starting at offset `edge_offset` of the current // data edge, and returns the result in `ReadResult.tree`. `ReadResult.n` // contains the 'bytes used` from the last / current data edge in the tree. // This allows users that mix regular navigation (using string views) and // 'read into cord' navigation to keep track of the current state, and which // bytes have been consumed from a navigator. // This function returns `ReadResult.tree = nullptr` if the requested length // exceeds the length of the tree starting at the current data edge. ReadResult Read(size_t edge_offset, size_t n); // Skips `n` bytes forward from the current data edge, returning the navigated // to data edge in `Position.edge` and `Position.offset` containing the offset // inside that data edge. Note that the state of the navigator is left // unchanged if `n` is smaller than the length of the current data edge. Position Skip(size_t n); // Resets this instance to the default / empty state. void Reset(); private: // Slow path for Next() if Next() reached the end of a leaf node. Backtracks // up the stack until it finds a node that has a 'next' position available, // and then does a 'front dive' towards the next leaf node. CordRep* NextUp(); // Slow path for Previous() if Previous() reached the beginning of a leaf // node. Backtracks up the stack until it finds a node that has a 'previous' // position available, and then does a 'back dive' towards the previous leaf // node. CordRep* PreviousUp(); // Generic implementation of InitFirst() and InitLast(). template CordRep* Init(CordRepBtree* tree); // `height_` contains the height of the current tree, or -1 if empty. int height_ = -1; // `index_` and `node_` contain the navigation state as the 'path' to the // current data edge which is at `node_[0]->Edge(index_[0])`. The contents // of these are undefined until the instance is initialized (`height_ >= 0`). uint8_t index_[CordRepBtree::kMaxDepth]; CordRepBtree* node_[CordRepBtree::kMaxDepth]; }; // Returns true if this instance is not empty. inline CordRepBtreeNavigator::operator bool() const { return height_ >= 0; } inline CordRepBtree* CordRepBtreeNavigator::btree() const { return height_ >= 0 ? node_[height_] : nullptr; } inline CordRep* CordRepBtreeNavigator::Current() const { assert(height_ >= 0); return node_[0]->Edge(index_[0]); } inline void CordRepBtreeNavigator::Reset() { height_ = -1; } inline CordRep* CordRepBtreeNavigator::InitFirst(CordRepBtree* tree) { return Init(tree); } inline CordRep* CordRepBtreeNavigator::InitLast(CordRepBtree* tree) { return Init(tree); } template inline CordRep* CordRepBtreeNavigator::Init(CordRepBtree* tree) { assert(tree != nullptr); assert(tree->size() > 0); assert(tree->height() <= CordRepBtree::kMaxHeight); int height = height_ = tree->height(); size_t index = tree->index(edge_type); node_[height] = tree; index_[height] = static_cast(index); while (--height >= 0) { tree = tree->Edge(index)->btree(); node_[height] = tree; index = tree->index(edge_type); index_[height] = static_cast(index); } return node_[0]->Edge(index); } inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::Seek( size_t offset) { assert(btree() != nullptr); int height = height_; CordRepBtree* edge = node_[height]; if (ABSL_PREDICT_FALSE(offset >= edge->length)) return {nullptr, 0}; CordRepBtree::Position index = edge->IndexOf(offset); index_[height] = static_cast(index.index); while (--height >= 0) { edge = edge->Edge(index.index)->btree(); node_[height] = edge; index = edge->IndexOf(index.n); index_[height] = static_cast(index.index); } return {edge->Edge(index.index), index.n}; } inline CordRepBtreeNavigator::Position CordRepBtreeNavigator::InitOffset( CordRepBtree* tree, size_t offset) { assert(tree != nullptr); assert(tree->height() <= CordRepBtree::kMaxHeight); if (ABSL_PREDICT_FALSE(offset >= tree->length)) return {nullptr, 0}; height_ = tree->height(); node_[height_] = tree; return Seek(offset); } inline CordRep* CordRepBtreeNavigator::Next() { CordRepBtree* edge = node_[0]; return index_[0] == edge->back() ? NextUp() : edge->Edge(++index_[0]); } inline CordRep* CordRepBtreeNavigator::Previous() { CordRepBtree* edge = node_[0]; return index_[0] == edge->begin() ? PreviousUp() : edge->Edge(--index_[0]); } inline CordRep* CordRepBtreeNavigator::NextUp() { assert(index_[0] == node_[0]->back()); CordRepBtree* edge; size_t index; int height = 0; do { if (++height > height_) return nullptr; edge = node_[height]; index = index_[height] + 1; } while (index == edge->end()); index_[height] = static_cast(index); do { node_[--height] = edge = edge->Edge(index)->btree(); index_[height] = static_cast(index = edge->begin()); } while (height > 0); return edge->Edge(index); } inline CordRep* CordRepBtreeNavigator::PreviousUp() { assert(index_[0] == node_[0]->begin()); CordRepBtree* edge; size_t index; int height = 0; do { if (++height > height_) return nullptr; edge = node_[height]; index = index_[height]; } while (index == edge->begin()); index_[height] = static_cast(--index); do { node_[--height] = edge = edge->Edge(index)->btree(); index_[height] = static_cast(index = edge->back()); } while (height > 0); return edge->Edge(index); } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORD_REP_BTREE_NAVIGATOR_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cord_rep_crc.h0000644000175000017510000000642514737212474024452 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_ #define ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_ #include #include #include "absl/base/config.h" #include "absl/base/optimization.h" #include "absl/crc/internal/crc_cord_state.h" #include "absl/strings/internal/cord_internal.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // CordRepCrc is a CordRep node intended only to appear at the top level of a // cord tree. It associates an "expected CRC" with the contained data, to allow // for easy passage of checksum data in Cord data flows. // // From Cord's perspective, the crc value has no semantics; any validation of // the contained checksum is the user's responsibility. struct CordRepCrc : public CordRep { CordRep* child; absl::crc_internal::CrcCordState crc_cord_state; // Consumes `child` and returns a CordRepCrc prefixed tree containing `child`. // If the specified `child` is itself a CordRepCrc node, then this method // either replaces the existing node, or directly updates the crc state in it // depending on the node being shared or not, i.e.: refcount.IsOne(). // `child` must only be null if the Cord is empty. Never returns null. static CordRepCrc* New(CordRep* child, crc_internal::CrcCordState state); // Destroys (deletes) the provided node. `node` must not be null. static void Destroy(CordRepCrc* node); }; // Consumes `rep` and returns a CordRep* with any outer CordRepCrc wrapper // removed. This is usually a no-op (returning `rep`), but this will remove and // unref an outer CordRepCrc node. inline CordRep* RemoveCrcNode(CordRep* rep) { assert(rep != nullptr); if (ABSL_PREDICT_FALSE(rep->IsCrc())) { CordRep* child = rep->crc()->child; if (rep->refcount.IsOne()) { delete rep->crc(); } else { CordRep::Ref(child); CordRep::Unref(rep); } return child; } return rep; } // Returns `rep` if it is not a CordRepCrc node, or its child if it is. // Does not consume or create a reference on `rep` or the returned value. inline CordRep* SkipCrcNode(CordRep* rep) { assert(rep != nullptr); if (ABSL_PREDICT_FALSE(rep->IsCrc())) { return rep->crc()->child; } else { return rep; } } inline const CordRep* SkipCrcNode(const CordRep* rep) { assert(rep != nullptr); if (ABSL_PREDICT_FALSE(rep->IsCrc())) { return rep->crc()->child; } else { return rep; } } inline CordRepCrc* CordRep::crc() { assert(IsCrc()); return static_cast(this); } inline const CordRepCrc* CordRep::crc() const { assert(IsCrc()); return static_cast(this); } } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/stringify_sink.h0000644000175000017510000000276614737212474025074 0ustar nileshnilesh// Copyright 2022 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ #define ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ #include #include #include #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { class StringifySink { public: void Append(size_t count, char ch); void Append(string_view v); // Support `absl::Format(&sink, format, args...)`. friend void AbslFormatFlush(StringifySink* sink, absl::string_view v) { sink->Append(v); } private: template friend string_view ExtractStringification(StringifySink& sink, const T& v); std::string buffer_; }; template string_view ExtractStringification(StringifySink& sink, const T& v) { AbslStringify(sink, v); return sink.buffer_; } } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STRINGIFY_SINK_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_sample_token.h0000644000175000017510000000716114737212474025706 0ustar nileshnilesh// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/base/config.h" #include "absl/strings/internal/cordz_handle.h" #include "absl/strings/internal/cordz_info.h" #ifndef ABSL_STRINGS_INTERNAL_CORDZ_SAMPLE_TOKEN_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_SAMPLE_TOKEN_H_ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // The existence of a CordzSampleToken guarantees that a reader can traverse the // global_cordz_infos_head linked-list without needing to hold a mutex. When a // CordzSampleToken exists, all CordzInfo objects that would be destroyed are // instead appended to a deletion queue. When the CordzSampleToken is destroyed, // it will also clean up any of these CordzInfo objects. // // E.g., ST are CordzSampleToken objects and CH are CordzHandle objects. // ST1 <- CH1 <- CH2 <- ST2 <- CH3 <- global_delete_queue_tail // // This list tracks that CH1 and CH2 were created after ST1, so the thread // holding ST1 might have a reference to CH1, CH2, ST2, and CH3. However, ST2 // was created later, so the thread holding the ST2 token cannot have a // reference to ST1, CH1, or CH2. If ST1 is cleaned up first, that thread will // delete ST1, CH1, and CH2. If instead ST2 is cleaned up first, that thread // will only delete ST2. // // If ST1 is cleaned up first, the new list will be: // ST2 <- CH3 <- global_delete_queue_tail // // If ST2 is cleaned up first, the new list will be: // ST1 <- CH1 <- CH2 <- CH3 <- global_delete_queue_tail // // All new CordzHandle objects are appended to the list, so if a new thread // comes along before either ST1 or ST2 are cleaned up, the new list will be: // ST1 <- CH1 <- CH2 <- ST2 <- CH3 <- ST3 <- global_delete_queue_tail // // A thread must hold the global_delete_queue_mu mutex whenever it's altering // this list. // // It is safe for thread that holds a CordzSampleToken to read // global_cordz_infos at any time since the objects it is able to retrieve will // not be deleted while the CordzSampleToken exists. class CordzSampleToken : public CordzSnapshot { public: class Iterator { public: using iterator_category = std::input_iterator_tag; using value_type = const CordzInfo&; using difference_type = ptrdiff_t; using pointer = const CordzInfo*; using reference = value_type; Iterator() = default; Iterator& operator++(); Iterator operator++(int); friend bool operator==(const Iterator& lhs, const Iterator& rhs); friend bool operator!=(const Iterator& lhs, const Iterator& rhs); reference operator*() const; pointer operator->() const; private: friend class CordzSampleToken; explicit Iterator(const CordzSampleToken* token); const CordzSampleToken* token_ = nullptr; pointer current_ = nullptr; }; CordzSampleToken() = default; CordzSampleToken(const CordzSampleToken&) = delete; CordzSampleToken& operator=(const CordzSampleToken&) = delete; Iterator begin() { return Iterator(this); } Iterator end() { return Iterator(); } }; } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_SAMPLE_TOKEN_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/string_constant.h0000644000175000017510000000501614737212474025240 0ustar nileshnilesh// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ #define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { // StringConstant represents a compile time string constant. // It can be accessed via its `absl::string_view value` static member. // It is guaranteed that the `string_view` returned has constant `.data()`, // constant `.size()` and constant `value[i]` for all `0 <= i < .size()` // // The `T` is an opaque type. It is guaranteed that different string constants // will have different values of `T`. This allows users to associate the string // constant with other static state at compile time. // // Instances should be made using the `MakeStringConstant()` factory function // below. template struct StringConstant { private: static constexpr bool TryConstexprEval(absl::string_view view) { return view.empty() || 2 * view[0] != 1; } public: static constexpr absl::string_view value = T{}(); constexpr absl::string_view operator()() const { return value; } // Check to be sure `view` points to constant data. // Otherwise, it can't be constant evaluated. static_assert(TryConstexprEval(value), "The input string_view must point to constant data."); }; #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL template constexpr absl::string_view StringConstant::value; #endif // Factory function for `StringConstant` instances. // It supports callables that have a constexpr default constructor and a // constexpr operator(). // It must return an `absl::string_view` or `const char*` pointing to constant // data. This is validated at compile time. template constexpr StringConstant MakeStringConstant(T) { return {}; } } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/numbers_test_common.h0000644000175000017510000001306214737212474026103 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // This file contains common things needed by numbers_test.cc, // numbers_legacy_test.cc and numbers_benchmark.cc. #ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ #define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ #include #include #include #include #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { template inline bool Itoa(IntType value, int base, std::string* destination) { destination->clear(); if (base <= 1 || base > 36) { return false; } if (value == 0) { destination->push_back('0'); return true; } bool negative = value < 0; while (value != 0) { const IntType next_value = value / base; // Can't use std::abs here because of problems when IntType is unsigned. int remainder = static_cast(value > next_value * base ? value - next_value * base : next_value * base - value); char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; destination->insert(0, 1, c); value = next_value; } if (negative) { destination->insert(0, 1, '-'); } return true; } struct uint32_test_case { const char* str; bool expect_ok; int base; // base to pass to the conversion function uint32_t expected; }; inline const std::array& strtouint32_test_cases() { static const std::array test_cases{{ {"0xffffffff", true, 16, (std::numeric_limits::max)()}, {"0x34234324", true, 16, 0x34234324}, {"34234324", true, 16, 0x34234324}, {"0", true, 16, 0}, {" \t\n 0xffffffff", true, 16, (std::numeric_limits::max)()}, {" \f\v 46", true, 10, 46}, // must accept weird whitespace {" \t\n 72717222", true, 8, 072717222}, {" \t\n 072717222", true, 8, 072717222}, {" \t\n 072717228", false, 8, 07271722}, {"0", true, 0, 0}, // Base-10 version. {"34234324", true, 0, 34234324}, {"4294967295", true, 0, (std::numeric_limits::max)()}, {"34234324 \n\t", true, 10, 34234324}, // Unusual base {"0", true, 3, 0}, {"2", true, 3, 2}, {"11", true, 3, 4}, // Invalid uints. {"", false, 0, 0}, {" ", false, 0, 0}, {"abc", false, 0, 0}, // would be valid hex, but prefix is missing {"34234324a", false, 0, 34234324}, {"34234.3", false, 0, 34234}, {"-1", false, 0, 0}, {" -123", false, 0, 0}, {" \t\n -123", false, 0, 0}, // Out of bounds. {"4294967296", false, 0, (std::numeric_limits::max)()}, {"0x100000000", false, 0, (std::numeric_limits::max)()}, {nullptr, false, 0, 0}, }}; return test_cases; } struct uint64_test_case { const char* str; bool expect_ok; int base; uint64_t expected; }; inline const std::array& strtouint64_test_cases() { static const std::array test_cases{{ {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, {"0", true, 16, 0}, {"000", true, 0, 0}, {"0", true, 0, 0}, {" \t\n 0xffffffffffffffff", true, 16, (std::numeric_limits::max)()}, {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, {"12845670123456701234", false, 8, 0}, // Base-10 version. {"34234324487834466", true, 0, int64_t{34234324487834466}}, {" \t\n 18446744073709551615", true, 0, (std::numeric_limits::max)()}, {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, {" \f\v 46", true, 10, 46}, // must accept weird whitespace // Unusual base {"0", true, 3, 0}, {"2", true, 3, 2}, {"11", true, 3, 4}, {"0", true, 0, 0}, // Invalid uints. {"", false, 0, 0}, {" ", false, 0, 0}, {"abc", false, 0, 0}, {"34234324487834466a", false, 0, 0}, {"34234487834466.3", false, 0, 0}, {"-1", false, 0, 0}, {" -123", false, 0, 0}, {" \t\n -123", false, 0, 0}, // Out of bounds. {"18446744073709551616", false, 10, 0}, {"18446744073709551616", false, 0, 0}, {"0x10000000000000000", false, 16, (std::numeric_limits::max)()}, {"0X10000000000000000", false, 16, (std::numeric_limits::max)()}, // 0X versus 0x. {"0x10000000000000000", false, 0, (std::numeric_limits::max)()}, {"0X10000000000000000", false, 0, (std::numeric_limits::max)()}, // 0X versus 0x. {"0x1234", true, 16, 0x1234}, // Base-10 string version. {"1234", true, 0, 1234}, {nullptr, false, 0, 0}, }}; return test_cases; } } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/resize_uninitialized.h0000644000175000017510000001051214737212474026247 0ustar nileshnilesh// // Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ #define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ #include #include #include #include #include "absl/base/port.h" #include "absl/meta/type_traits.h" // for void_t namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { // In this type trait, we look for a __resize_default_init member function, and // we use it if available, otherwise, we use resize. We provide HasMember to // indicate whether __resize_default_init is present. template struct ResizeUninitializedTraits { using HasMember = std::false_type; static void Resize(string_type* s, size_t new_size) { s->resize(new_size); } }; // __resize_default_init is provided by libc++ >= 8.0 template struct ResizeUninitializedTraits< string_type, absl::void_t() .__resize_default_init(237))> > { using HasMember = std::true_type; static void Resize(string_type* s, size_t new_size) { s->__resize_default_init(new_size); } }; // Returns true if the std::string implementation supports a resize where // the new characters added to the std::string are left untouched. // // (A better name might be "STLStringSupportsUninitializedResize", alluding to // the previous function.) template inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { return ResizeUninitializedTraits::HasMember::value; } // Like str->resize(new_size), except any new characters added to "*str" as a // result of resizing may be left uninitialized, rather than being filled with // '0' bytes. Typically used when code is then going to overwrite the backing // store of the std::string with known data. template inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { ResizeUninitializedTraits::Resize(s, new_size); } // Used to ensure exponential growth so that the amortized complexity of // increasing the string size by a small amount is O(1), in contrast to // O(str->size()) in the case of precise growth. template void STLStringReserveAmortized(string_type* s, size_t new_size) { const size_t cap = s->capacity(); if (new_size > cap) { // Make sure to always grow by at least a factor of 2x. s->reserve((std::max)(new_size, 2 * cap)); } } // In this type trait, we look for an __append_default_init member function, and // we use it if available, otherwise, we use append. template struct AppendUninitializedTraits { static void Append(string_type* s, size_t n) { s->append(n, typename string_type::value_type()); } }; template struct AppendUninitializedTraits< string_type, absl::void_t() .__append_default_init(237))> > { static void Append(string_type* s, size_t n) { s->__append_default_init(n); } }; // Like STLStringResizeUninitialized(str, new_size), except guaranteed to use // exponential growth so that the amortized complexity of increasing the string // size by a small amount is O(1), in contrast to O(str->size()) in the case of // precise growth. template void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) { const size_t size = s->size(); if (new_size > size) { AppendUninitializedTraits::Append(s, new_size - size); } else { s->erase(new_size); } } } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_update_tracker.h0000644000175000017510000000742114737212474026221 0ustar nileshnilesh// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ #include #include #include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // CordzUpdateTracker tracks counters for Cord update methods. // // The purpose of CordzUpdateTracker is to track the number of calls to methods // updating Cord data for sampled cords. The class internally uses 'lossy' // atomic operations: Cord is thread-compatible, so there is no need to // synchronize updates. However, Cordz collection threads may call 'Value()' at // any point, so the class needs to provide thread safe access. // // This class is thread-safe. But as per above comments, all non-const methods // should be used single-threaded only: updates are thread-safe but lossy. class CordzUpdateTracker { public: // Tracked update methods. enum MethodIdentifier { kUnknown, kAppendCord, kAppendCordBuffer, kAppendExternalMemory, kAppendString, kAssignCord, kAssignString, kClear, kConstructorCord, kConstructorString, kCordReader, kFlatten, kGetAppendBuffer, kGetAppendRegion, kMakeCordFromExternal, kMoveAppendCord, kMoveAssignCord, kMovePrependCord, kPrependCord, kPrependCordBuffer, kPrependString, kRemovePrefix, kRemoveSuffix, kSetExpectedChecksum, kSubCord, // kNumMethods defines the number of entries: must be the last entry. kNumMethods, }; // Constructs a new instance. All counters are zero-initialized. constexpr CordzUpdateTracker() noexcept : values_{} {} // Copy constructs a new instance. CordzUpdateTracker(const CordzUpdateTracker& rhs) noexcept { *this = rhs; } // Assigns the provided value to this instance. CordzUpdateTracker& operator=(const CordzUpdateTracker& rhs) noexcept { for (int i = 0; i < kNumMethods; ++i) { values_[i].store(rhs.values_[i].load(std::memory_order_relaxed), std::memory_order_relaxed); } return *this; } // Returns the value for the specified method. int64_t Value(MethodIdentifier method) const { return values_[method].load(std::memory_order_relaxed); } // Increases the value for the specified method by `n` void LossyAdd(MethodIdentifier method, int64_t n = 1) { auto& value = values_[method]; value.store(value.load(std::memory_order_relaxed) + n, std::memory_order_relaxed); } // Adds all the values from `src` to this instance void LossyAdd(const CordzUpdateTracker& src) { for (int i = 0; i < kNumMethods; ++i) { MethodIdentifier method = static_cast(i); if (int64_t value = src.Value(method)) { LossyAdd(method, value); } } } private: // Until C++20 std::atomic is not constexpr default-constructible, so we need // a wrapper for this class to be constexpr constructible. class Counter : public std::atomic { public: constexpr Counter() noexcept : std::atomic(0) {} }; Counter values_[kNumMethods]; }; } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_UPDATE_TRACKER_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/cordz_functions.h0000644000175000017510000000506314737212474025234 0ustar nileshnilesh// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ #define ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/optimization.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { // Returns the current sample rate. This represents the average interval // between samples. int32_t get_cordz_mean_interval(); // Sets the sample rate with the average interval between samples. void set_cordz_mean_interval(int32_t mean_interval); // Cordz is only enabled on Linux with thread_local support. #if defined(ABSL_INTERNAL_CORDZ_ENABLED) #error ABSL_INTERNAL_CORDZ_ENABLED cannot be set directly #elif defined(__linux__) && defined(ABSL_HAVE_THREAD_LOCAL) #define ABSL_INTERNAL_CORDZ_ENABLED 1 #endif #ifdef ABSL_INTERNAL_CORDZ_ENABLED // cordz_next_sample is the number of events until the next sample event. If // the value is 1 or less, the code will check on the next event if cordz is // enabled, and if so, will sample the Cord. cordz is only enabled when we can // use thread locals. ABSL_CONST_INIT extern thread_local int64_t cordz_next_sample; // Determines if the next sample should be profiled. If it is, the value pointed // at by next_sample will be set with the interval until the next sample. bool cordz_should_profile_slow(); // Returns true if the next cord should be sampled. inline bool cordz_should_profile() { if (ABSL_PREDICT_TRUE(cordz_next_sample > 1)) { cordz_next_sample--; return false; } return cordz_should_profile_slow(); } // Sets the interval until the next sample (for testing only) void cordz_set_next_sample_for_testing(int64_t next_sample); #else // ABSL_INTERNAL_CORDZ_ENABLED inline bool cordz_should_profile() { return false; } inline void cordz_set_next_sample_for_testing(int64_t) {} #endif // ABSL_INTERNAL_CORDZ_ENABLED } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CORDZ_FUNCTIONS_H_ s2/tools/vendor/abseil-cpp/absl/strings/internal/stl_type_traits.h0000644000175000017510000002571414737212474025261 0ustar nileshnilesh// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // The file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type // trait metafunction to assist in working with the _GLIBCXX_DEBUG debug // wrappers of STL containers. // // DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including // absl/strings/str_split.h. // // IWYU pragma: private, include "absl/strings/str_split.h" #ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ #define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ #include #include #include #include #include #include #include #include #include #include #include #include "absl/meta/type_traits.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { template class T> struct IsSpecializationImpl : std::false_type {}; template