/src/lib/string/abstract_string.e

http://github.com/tybor/Liberty · Specman e · 1420 lines · 1080 code · 76 blank · 264 comment · 77 complexity · 54013e666f8f6a744d76535ad7f042fb MD5 · raw file

  1. -- This file is part of a Liberty Eiffel library.
  2. -- See the full copyright at the end.
  3. --
  4. deferred class ABSTRACT_STRING
  5. --
  6. -- Character STRINGs indexed from `1' to `count'.
  7. --
  8. -- See also FIXED_STRING and STRING
  9. inherit
  10. HASHABLE
  11. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory
  12. end
  13. COMPARABLE
  14. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal, compare, three_way_comparison,
  15. infix ">", infix "<=", infix ">="
  16. end
  17. STORABLE
  18. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  19. end
  20. TRAVERSABLE[CHARACTER]
  21. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  22. end
  23. SEARCHABLE[CHARACTER]
  24. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  25. end
  26. insert
  27. PLATFORM
  28. redefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  29. end
  30. RECYCLABLE
  31. undefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  32. end
  33. STRING_HANDLER
  34. undefine print_on, copy, out_in_tagged_out_memory, fill_tagged_out_memory, is_equal
  35. end
  36. feature {ANY}
  37. lower: INTEGER 1
  38. -- Minimum index; actually, this is always 1 (this feature
  39. -- here to mimic the one of the COLLECTION hierarchy).
  40. --
  41. -- See also `upper', `valid_index', `item'.
  42. upper: INTEGER
  43. -- Maximum index; actually the same value as `count' (this
  44. -- feature is here to mimic the one of the COLLECTION hierarchy).
  45. --
  46. -- See also `lower', `valid_index', `item'.
  47. do
  48. Result := count
  49. ensure
  50. Result = count
  51. end
  52. copy (other: like Current)
  53. deferred
  54. ensure then
  55. count = other.count
  56. end
  57. print_on (file: OUTPUT_STREAM)
  58. do
  59. file.put_abstract_string(Current)
  60. end
  61. feature {ANY} -- Testing:
  62. is_empty: BOOLEAN
  63. -- Has string length 0?
  64. --
  65. -- See also `count'.
  66. do
  67. Result := count = 0
  68. end
  69. item (i: INTEGER): CHARACTER
  70. -- Character at position `i'.
  71. --
  72. -- See also `lower', `upper', `valid_index', `put'.
  73. deferred
  74. end
  75. frozen infix "@" (i: INTEGER): CHARACTER
  76. -- The infix notation which is actually just a synonym for `item'.
  77. --
  78. -- See also `item', `put'.
  79. require
  80. valid_index: valid_index(i)
  81. do
  82. Result := item(i)
  83. ensure
  84. definition: Result = item(i)
  85. end
  86. infix "^" (a_range: INTEGER_RANGE[INTEGER]): ABSTRACT_STRING
  87. -- Substring of items in `a_range' .
  88. require valid_range: valid_index(a_range.lower) and valid_index(a_range.upper)
  89. do
  90. Result := substring(a_range.lower, a_range.upper)
  91. ensure
  92. Result.count = a_range.count
  93. has_substring(Result) -- This is the same of writing "substring_index(Result,lower)=a_range.lower"
  94. end
  95. infix "<" (other: ABSTRACT_STRING): BOOLEAN
  96. -- Is `Current' less than `other'?
  97. --
  98. -- See also `>', `<=', `>=', `min', `max'.
  99. local
  100. i: INTEGER; maxi: INTEGER
  101. do
  102. from
  103. i := lower
  104. maxi := count.min(other.count)
  105. until
  106. i > maxi or else item(i) /= other.item(i)
  107. loop
  108. i := i + 1
  109. end
  110. if i <= maxi then
  111. Result := item(i) < other.item(i)
  112. else
  113. Result := i <= other.count
  114. end
  115. end
  116. infix "<=" (other: ABSTRACT_STRING): BOOLEAN
  117. do
  118. Result := not (other < Current)
  119. end
  120. infix ">" (other: ABSTRACT_STRING): BOOLEAN
  121. do
  122. Result := other < Current
  123. end
  124. infix ">=" (other: ABSTRACT_STRING): BOOLEAN
  125. do
  126. Result := not (Current < other)
  127. end
  128. compare, three_way_comparison (other: ABSTRACT_STRING): INTEGER
  129. local
  130. i: INTEGER; maxi: INTEGER
  131. do
  132. from
  133. i := lower
  134. maxi := count.min(other.count)
  135. until
  136. i > maxi or else item(i) /= other.item(i)
  137. loop
  138. i := i + 1
  139. end
  140. if count < i then
  141. if other.count < i then
  142. else
  143. Result := -1
  144. end
  145. elseif other.count < i then
  146. Result := 1
  147. elseif item(i) < other.item(i) then
  148. Result := -1
  149. else
  150. Result := 1
  151. end
  152. end
  153. is_equal (other: ABSTRACT_STRING): BOOLEAN
  154. -- Do both strings have the same character sequence?
  155. --
  156. -- See also `same_as'.
  157. deferred
  158. end
  159. same_as (other: ABSTRACT_STRING): BOOLEAN
  160. -- Case insensitive `is_equal'.
  161. require
  162. other /= Void
  163. deferred
  164. end
  165. item_code (i: INTEGER): INTEGER
  166. -- Code of character at position `i'.
  167. --
  168. -- See also `item'.
  169. require
  170. valid_index: valid_index(i)
  171. do
  172. -- TODO: find any technically sound reason to restore previous
  173. -- implementation: "Result := storage.item(i - 1).code"
  174. Result := item(i).code
  175. ensure
  176. definition: Result = item(i).code
  177. end
  178. first_index_of, fast_first_index_of (c: CHARACTER): INTEGER
  179. -- Index of first occurrence of `c', `upper` + 1 if none.
  180. --
  181. -- See also `last_index_of', `index_of', `reverse_index_of'.
  182. do
  183. Result := index_of(c, lower)
  184. end
  185. last_index_of, fast_last_index_of (c: CHARACTER): INTEGER
  186. -- Index of last occurrence of `c', `lower` - 1 if none.
  187. --
  188. -- See also `first_index_of', `reverse_index_of', `index_of'.
  189. do
  190. Result := reverse_index_of(c, upper)
  191. end
  192. has_substring (other: ABSTRACT_STRING): BOOLEAN
  193. -- True if `Current' contains `other'.
  194. --
  195. -- See also `substring_index', `has'.
  196. require
  197. other_not_void: other /= Void
  198. do
  199. Result := substring_index(other, lower)>=lower
  200. end
  201. occurrences (c: CHARACTER): INTEGER
  202. -- Number of times character `c' appears in the string.
  203. --
  204. -- See also `remove_all_occurrences', `has'.
  205. deferred
  206. ensure
  207. Result >= 0
  208. end
  209. has_suffix (s: ABSTRACT_STRING): BOOLEAN
  210. -- True if suffix of `Current' is `s'.
  211. --
  212. -- See also `remove_suffix', `has_prefix', `has_substring'.
  213. require
  214. s /= Void
  215. local
  216. i1, i2: INTEGER
  217. do
  218. if s.count <= count then
  219. from
  220. i1 := count - s.count + lower
  221. i2 := lower
  222. until
  223. i1 > count or else item(i1) /= s.item(i2)
  224. loop
  225. i1 := i1 + 1
  226. i2 := i2 + 1
  227. end
  228. Result := i1 > count
  229. end
  230. end
  231. has_prefix (p: ABSTRACT_STRING): BOOLEAN
  232. -- True if prefix of `Current' is `p'.
  233. --
  234. -- See also `remove_prefix', `has_suffix', `has_substring'.
  235. require
  236. p /= Void
  237. local
  238. i, ip: INTEGER
  239. do
  240. if p.count <= count then
  241. from
  242. i := lower + p.count - 1
  243. ip := p.upper
  244. until
  245. i < lower or else item(i) /= p.item(ip)
  246. loop
  247. i := i - 1
  248. ip := ip - 1
  249. end
  250. Result := i < lower
  251. end
  252. end
  253. feature {ANY} -- Testing and Conversion:
  254. is_ascii: BOOLEAN
  255. -- Is `Current' only made of (7 bit) ASCII characters?
  256. local
  257. i: INTEGER
  258. do
  259. from
  260. i := upper
  261. Result := True
  262. until
  263. i < lower or else not Result
  264. loop
  265. Result := item(i).is_ascii
  266. i := i - 1
  267. end
  268. ensure
  269. Result = for_all(agent {CHARACTER}.is_ascii)
  270. end
  271. is_boolean: BOOLEAN
  272. -- Does `Current' represent a BOOLEAN?
  273. -- Valid BOOLEANs are "True" and "False".
  274. do
  275. Result := (once "True").is_equal(Current) or else (once "False").is_equal(Current)
  276. end
  277. to_boolean: BOOLEAN
  278. -- Boolean value
  279. -- "True" yields True, "False" yields False (what a surprise).
  280. require
  281. represents_a_boolean: is_boolean
  282. do
  283. Result := (once "True").is_equal(Current)
  284. end
  285. is_integer: BOOLEAN
  286. -- Does 'Current' represent an INTEGER?
  287. -- `Result' is True if and only if the following two conditions
  288. -- hold:
  289. --
  290. -- 1. In the following BNF grammar, the value of `Current' can be
  291. -- produced by "Integer_literal", if leading and trailing
  292. -- separators are ignored:
  293. --
  294. -- Integer_literal = [Sign] Integer
  295. -- Sign = "+" | "-"
  296. -- Integer = Digit | Digit Integer
  297. -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
  298. --
  299. -- 2. The numerical value represented by `Current' is within the
  300. -- range that can be represented by an instance of type INTEGER.
  301. local
  302. i, state, value, bound, critical_bound: INTEGER; cc: CHARACTER
  303. do
  304. -- state 0: nothing read.
  305. -- state 1: "+" or "-" read.
  306. -- state 2: error.
  307. -- state 3: in the number.
  308. -- state 4: last digit of a critically big number
  309. -- state 5: after the number.
  310. from
  311. i := lower
  312. variant
  313. upper - i
  314. until
  315. state = 2 or else i > upper
  316. loop
  317. cc := item(i)
  318. inspect
  319. state
  320. when 0 then
  321. if cc.is_separator then
  322. elseif cc = '+' then
  323. bound := Maximum_integer #\\ 10
  324. critical_bound := Maximum_integer #// 10
  325. state := 1
  326. elseif cc = '-' then
  327. bound := -(Minimum_integer #\\ 10)
  328. critical_bound := -(Minimum_integer #// 10)
  329. state := 1
  330. elseif cc.is_digit then
  331. bound := Maximum_integer #\\ 10
  332. critical_bound := Maximum_integer #// 10
  333. value := cc.decimal_value
  334. state := 3
  335. else
  336. state := 2
  337. end
  338. when 1 then
  339. if cc.is_digit then
  340. value := cc.decimal_value
  341. state := 3
  342. else
  343. state := 2
  344. end
  345. when 3 then
  346. if cc.is_digit then
  347. value := 10 * value + cc.decimal_value
  348. if value >= critical_bound then
  349. state := 4
  350. end
  351. elseif cc.is_separator then
  352. state := 5
  353. else
  354. state := 2
  355. end
  356. when 4 then
  357. if cc.is_digit then
  358. if value > critical_bound then
  359. state := 2
  360. else
  361. if cc.decimal_value <= bound then
  362. state := 5
  363. else
  364. state := 2
  365. end
  366. end
  367. elseif cc.is_separator then
  368. state := 5
  369. else
  370. state := 2
  371. end
  372. when 5 then
  373. if cc.is_separator then
  374. else
  375. state := 2
  376. end
  377. end
  378. i := i + 1
  379. end
  380. Result := state >= 3
  381. end
  382. to_integer: INTEGER
  383. -- `Current' must look like an INTEGER.
  384. require
  385. is_integer
  386. local
  387. i: INTEGER; cc: CHARACTER; negative: BOOLEAN
  388. do
  389. from
  390. i := lower
  391. variant
  392. count - i
  393. until
  394. not item(i).is_separator
  395. loop
  396. i := i + 1
  397. end
  398. cc := item(i)
  399. i := i + 1
  400. if cc = '+' then
  401. cc := item(i)
  402. i := i + 1
  403. elseif cc = '-' then
  404. negative := True
  405. cc := item(i)
  406. i := i + 1
  407. end
  408. check
  409. cc.is_digit
  410. end
  411. Result := -cc.value
  412. from
  413. variant
  414. count - i
  415. until
  416. i > count
  417. loop
  418. cc := item(i)
  419. if cc.is_digit then
  420. Result := 10 * Result - cc.decimal_value -- Should not overflow since `is_integer' is true
  421. else
  422. check
  423. cc.is_separator
  424. end
  425. i := count -- terminate the loop
  426. end
  427. i := i + 1
  428. end
  429. if negative then
  430. else
  431. Result := -Result
  432. end
  433. end
  434. is_integer_64: BOOLEAN
  435. -- Does 'Current' represent an INTEGER_64?
  436. -- `Result' is True if and only if the following two conditions
  437. -- hold:
  438. --
  439. -- 1. In the following BNF grammar, the value of `Current' can be
  440. -- produced by "Integer_literal", if leading and trailing
  441. -- separators are ignored:
  442. --
  443. -- Integer_literal = [Sign] Integer
  444. -- Sign = "+" | "-"
  445. -- Integer = Digit | Digit Integer
  446. -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
  447. --
  448. -- 2. The numerical value represented by `Current' is within the
  449. -- range that can be represented by an instance of type INTEGER_64.
  450. local
  451. i, state: INTEGER; value, bound, critical_bound: INTEGER_64; cc: CHARACTER
  452. do
  453. -- state 0: nothing read.
  454. -- state 1: "+" or "-" read.
  455. -- state 2: error.
  456. -- state 3: in the number.
  457. -- state 4: last digit of a critically big number
  458. -- state 5: after the number.
  459. from
  460. i := lower
  461. variant
  462. count - i
  463. until
  464. state = 2 or else i > count
  465. loop
  466. cc := item(i)
  467. inspect
  468. state
  469. when 0 then
  470. if cc.is_separator then
  471. elseif cc = '+' then
  472. bound := Maximum_integer_64 #\\ 10
  473. critical_bound := Maximum_integer_64 #// 10
  474. state := 1
  475. elseif cc = '-' then
  476. bound := -(Minimum_integer_64 #\\ 10)
  477. critical_bound := -(Minimum_integer_64 #// 10)
  478. state := 1
  479. elseif cc.is_digit then
  480. bound := Maximum_integer_64 #\\ 10
  481. critical_bound := Maximum_integer_64 #// 10
  482. value := cc.decimal_value
  483. state := 3
  484. else
  485. state := 2
  486. end
  487. when 1 then
  488. if cc.is_digit then
  489. value := cc.decimal_value
  490. state := 3
  491. else
  492. state := 2
  493. end
  494. when 3 then
  495. if cc.is_digit then
  496. value := 10 * value + cc.decimal_value
  497. if value >= critical_bound then
  498. state := 4
  499. end
  500. elseif cc.is_separator then
  501. state := 5
  502. else
  503. state := 2
  504. end
  505. when 4 then
  506. if cc.is_digit then
  507. if value > critical_bound then
  508. state := 2
  509. else
  510. if cc.decimal_value <= bound then
  511. state := 5
  512. else
  513. state := 2
  514. end
  515. end
  516. elseif cc.is_separator then
  517. state := 5
  518. else
  519. state := 2
  520. end
  521. when 5 then
  522. if cc.is_separator then
  523. else
  524. state := 2
  525. end
  526. end
  527. i := i + 1
  528. end
  529. Result := state >= 3
  530. end
  531. to_integer_64: INTEGER_64
  532. -- `Current' must look like an INTEGER_64.
  533. require
  534. is_integer_64
  535. local
  536. i: INTEGER; cc: CHARACTER; negative: BOOLEAN
  537. do
  538. from
  539. i := lower
  540. variant
  541. count - i
  542. until
  543. not item(i).is_separator
  544. loop
  545. i := i + 1
  546. end
  547. cc := item(i)
  548. i := i + 1
  549. if cc = '+' then
  550. cc := item(i)
  551. i := i + 1
  552. elseif cc = '-' then
  553. negative := True
  554. cc := item(i)
  555. i := i + 1
  556. end
  557. check
  558. cc.is_digit
  559. end
  560. Result := -cc.value
  561. from
  562. variant
  563. count - i
  564. until
  565. i > count
  566. loop
  567. cc := item(i)
  568. if cc.is_digit then
  569. Result := 10 * Result - cc.decimal_value -- Should not overflow since `is_integer_64' is true
  570. else
  571. check
  572. cc.is_separator
  573. end
  574. i := count -- terminate the loop
  575. end
  576. i := i + 1
  577. end
  578. if negative then
  579. else
  580. Result := -Result
  581. end
  582. end
  583. is_real: BOOLEAN
  584. -- Can contents be read as a REAL ?
  585. -- Fails for numbers where the base or "10 ^ exponent" are not in
  586. -- the range `Minimum_real' ... `Maximum_real'. Parsing is done
  587. -- positive. That means if `Minimum_real.abs' is not equal to
  588. -- `Maximum_real' it will not work correctly. Furthermore the
  589. -- arithmetic package used must support the value 'inf' for a
  590. -- number greater than Maximum_real.
  591. -- `Result' is True if and only if the following two conditions
  592. -- hold:
  593. --
  594. -- 1. In the following BNF grammar, the value of `Current' can be
  595. -- produced by "Real_literal", if leading or trailing separators
  596. -- are ignored.
  597. --
  598. -- Real_literal = Mantissa [Exponent_part]
  599. -- Exponent_part = "E" Exponent
  600. -- | "e" Exponent
  601. -- Exponent = Integer_literal
  602. -- Mantissa = Decimal_literal
  603. -- Decimal_literal = Integer_literal ["." Integer]
  604. -- Integer_literal = [Sign] Integer
  605. -- Sign = "+" | "-"
  606. -- Integer = Digit | Digit Integer
  607. -- Digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
  608. --
  609. --
  610. -- 2. The numerical value represented by `Current' is within the
  611. -- range that can be represented by an instance of type REAL.
  612. local
  613. i, state: INTEGER; cc: CHARACTER; base, exp, value, multiplier: REAL; negative, neg_exp: BOOLEAN
  614. do
  615. -- state 0: nothing read.
  616. -- state 1: "+" or "-" read.
  617. -- state 2: in the number.
  618. -- state 3: decimal point read
  619. -- state 4: in fractional part
  620. -- state 5: read 'E' or 'e' for scientific notation
  621. -- state 6: read "-" or "+" sign of exponent
  622. -- state 7: in exponent
  623. -- state 8: after the number.
  624. -- state 9: error.
  625. from
  626. i := lower
  627. variant
  628. count - i
  629. until
  630. state = 9 or else i > count
  631. loop
  632. cc := item(i)
  633. inspect
  634. state
  635. when 0 then
  636. if cc.is_separator then
  637. elseif cc = '+' then
  638. state := 1
  639. elseif cc = '-' then
  640. negative := True
  641. state := 1
  642. elseif cc.is_digit then
  643. base := cc.decimal_value
  644. state := 2
  645. elseif cc = '.' then
  646. state := 3
  647. else
  648. state := 9
  649. end
  650. when 1 then
  651. if cc.is_digit then
  652. base := cc.decimal_value
  653. state := 2
  654. elseif cc = '.' then
  655. state := 3
  656. else
  657. state := 9
  658. end
  659. when 2 then
  660. if cc.is_digit then
  661. base := base * 10 + cc.decimal_value
  662. elseif cc = '.' then
  663. state := 3
  664. elseif cc = 'e' or else cc = 'E' then
  665. state := 5
  666. elseif cc.is_separator then
  667. state := 8
  668. else
  669. state := 9
  670. end
  671. when 3 then
  672. multiplier := 0.1
  673. if cc.is_digit then
  674. base := base + multiplier * cc.decimal_value
  675. state := 4
  676. else
  677. state := 9
  678. end
  679. when 4 then
  680. multiplier := multiplier * 0.1
  681. if cc.is_digit then
  682. base := base + multiplier * cc.decimal_value
  683. elseif cc.is_separator then
  684. state := 8
  685. elseif cc = 'e' or else cc = 'E' then
  686. state := 5
  687. else
  688. state := 9
  689. end
  690. when 5 then
  691. if cc = '-' then
  692. neg_exp := True
  693. state := 6
  694. elseif cc = '+' then
  695. state := 6
  696. elseif cc.is_digit then
  697. exp := cc.decimal_value
  698. state := 7
  699. else
  700. state := 9
  701. end
  702. when 6 then
  703. if cc.is_digit then
  704. exp := cc.decimal_value
  705. state := 7
  706. else
  707. state := 9
  708. end
  709. when 7 then
  710. if cc.is_digit then
  711. exp := exp * 10 + cc.decimal_value
  712. elseif cc.is_separator then
  713. state := 8
  714. else
  715. state := 9
  716. end
  717. when 8 then
  718. if cc.is_separator then
  719. else
  720. state := 9
  721. end
  722. end
  723. i := i + 1
  724. end
  725. if state /= 0 and then state /= 9 and then state /= 1 then
  726. Result := True
  727. if neg_exp then
  728. exp := -1 * exp
  729. end
  730. value := base * 10.0.pow(exp)
  731. if value > Maximum_real then
  732. -- can only happen if value = inf
  733. Result := False
  734. end
  735. end
  736. end
  737. to_real: REAL
  738. -- Conversion to the corresponding REAL value. The string must looks like a REAL (or like an
  739. -- INTEGER because the fractional part is optional). For an exact definition see 'is_real'.
  740. -- Note that this conversion might not be exact.
  741. require
  742. represents_a_real: is_real
  743. local
  744. i, state: INTEGER; cc: CHARACTER; base, exp, multiplier: REAL; negative, neg_exp: BOOLEAN
  745. do
  746. -- state 0: nothing read.
  747. -- state 1: "+" or "-" read.
  748. -- state 2: in the number.
  749. -- state 3: decimal point read
  750. -- state 4: in fractional part
  751. -- state 5: read 'E' or 'e' for scientific notation
  752. -- state 6: read "-" or "+" sign of exponent
  753. -- state 7: in exponent
  754. -- state 8: after the number.
  755. from
  756. i := lower
  757. variant
  758. count - i
  759. until
  760. i > count
  761. loop
  762. cc := item(i)
  763. inspect
  764. state
  765. when 0 then
  766. if cc.is_separator then
  767. elseif cc = '+' then
  768. state := 1
  769. elseif cc = '-' then
  770. negative := True
  771. state := 1
  772. elseif cc.is_digit then
  773. base := cc.decimal_value
  774. state := 2
  775. else
  776. -- cc = '.'
  777. state := 3
  778. end
  779. when 1 then
  780. if cc.is_digit then
  781. base := cc.decimal_value
  782. state := 2
  783. else
  784. -- cc = '.'
  785. state := 3
  786. end
  787. when 2 then
  788. if cc.is_digit then
  789. base := base * 10 + cc.decimal_value
  790. elseif cc = '.' then
  791. state := 3
  792. elseif cc.is_separator then
  793. state := 8
  794. else
  795. -- cc = 'e' or else cc = 'E'
  796. state := 5
  797. end
  798. when 3 then
  799. multiplier := 0.1
  800. if cc.is_separator then
  801. state := 8
  802. else
  803. -- cc.is_digit
  804. base := base + multiplier * cc.decimal_value
  805. state := 4
  806. end
  807. when 4 then
  808. multiplier := multiplier * 0.1
  809. if cc.is_digit then
  810. base := base + multiplier * cc.decimal_value
  811. elseif cc.is_separator then
  812. state := 8
  813. else
  814. -- cc = 'e' or else cc = 'E'
  815. state := 5
  816. end
  817. when 5 then
  818. if cc = '-' then
  819. neg_exp := True
  820. state := 6
  821. elseif cc = '+' then
  822. state := 6
  823. else
  824. -- cc.is_digit
  825. exp := cc.decimal_value
  826. state := 7
  827. end
  828. when 6 then
  829. -- cc.is_digit
  830. exp := cc.decimal_value
  831. state := 7
  832. when 7 then
  833. if cc.is_digit then
  834. exp := exp * 10 + cc.decimal_value
  835. else
  836. -- cc.is_separator
  837. state := 8
  838. end
  839. when 8 then
  840. -- cc.is_separator
  841. i := count -- terminate the loop
  842. end
  843. i := i + 1
  844. end
  845. if neg_exp then
  846. exp := -1 * exp
  847. end
  848. if negative then
  849. Result := -1 * base * 10.0.pow(exp)
  850. else
  851. Result := base * 10.0.pow(exp)
  852. end
  853. end
  854. is_number: BOOLEAN
  855. -- Can contents be read as a NUMBER?
  856. local
  857. number_tools: NUMBER_TOOLS
  858. do
  859. Result := number_tools.is_number(Current)
  860. end
  861. to_number: NUMBER
  862. -- Current must looks like an INTEGER.
  863. require
  864. is_number
  865. local
  866. number_tools: NUMBER_TOOLS
  867. do
  868. Result := number_tools.from_string(Current)
  869. end
  870. is_bit: BOOLEAN
  871. -- True when the contents is a sequence of bits (i.e., mixed
  872. -- characters `0' and characters `1').
  873. local
  874. i: INTEGER
  875. do
  876. from
  877. i := count
  878. Result := True
  879. until
  880. not Result or else i < lower
  881. loop
  882. Result := item(i).is_bit
  883. i := i - 1
  884. end
  885. ensure
  886. Result = (count = occurrences('0') + occurrences('1'))
  887. end
  888. binary_to_integer: INTEGER
  889. -- Assume there is enough space in the INTEGER to store
  890. -- the corresponding decimal value.
  891. require
  892. is_bit
  893. count <= Integer_bits
  894. local
  895. i: INTEGER
  896. do
  897. from
  898. i := lower
  899. until
  900. i > count
  901. loop
  902. if item(i) = '1' then
  903. Result := Result |<< 1 + 1
  904. else
  905. Result := Result |<< 1
  906. end
  907. i := i + 1
  908. end
  909. end
  910. feature {ANY} -- Concatenation
  911. infix "+" (other: ABSTRACT_STRING): STRING
  912. -- Create a new STRING which is the concatenation of `Current' and `other'.
  913. --
  914. -- See also `append'.
  915. require
  916. other_exists: other /= Void
  917. do
  918. create Result.make(count + other.count)
  919. Result.append(Current)
  920. Result.append(other)
  921. ensure
  922. result_count: Result.count = count + other.count
  923. end
  924. infix "|" (other: ABSTRACT_STRING): ROPE
  925. -- Current and `other' concatenated into a new ROPE, an ABSTRACT_STRING that can be efficiently
  926. -- concatenated.
  927. require
  928. other_exists: other /= Void
  929. do
  930. create Result.from_strings(Current,other)
  931. ensure
  932. Result.out.is_equal(Current + other)
  933. end
  934. infix "&" (other: ABSTRACT_STRING): ABSTRACT_STRING
  935. -- Current and `other' concatenating into a new object. The actual effective type of Result
  936. -- chosen by the implementation, possibly based on heuristics.
  937. require
  938. other_exists: other /= Void
  939. deferred
  940. ensure
  941. Result.out.is_equal(Current + other)
  942. end
  943. arg (an_index: INTEGER; a_value: ABSTRACT_STRING): ABSTRACT_STRING
  944. -- A copy of Current with the placeholder "#(an_index)" is replaced (if present) with the content of `a_value'.
  945. local
  946. i, backtrack_i: INTEGER
  947. index: INTEGER
  948. state: INTEGER
  949. ch: CHARACTER
  950. delimeter, opening_brace, closing_brace: CHARACTER
  951. accumulator: STRING
  952. do
  953. delimeter := '#'; opening_brace := '('; closing_brace := ')'
  954. -- The above constants are not put in the class to avoid "polluting"
  955. -- its namespace. Feel free to move it outside this feature if it
  956. -- fitter, i.e. redefining them in an heir.
  957. accumulator := ""
  958. Result := accumulator
  959. from i := lower; state := normal_state
  960. until i > upper
  961. loop
  962. from until i > upper loop
  963. ch := item(i)
  964. inspect state
  965. when always_print_state then
  966. accumulator.append_character(ch)
  967. state := normal_state
  968. when normal_state then
  969. if ch.is_equal(delimeter) then
  970. backtrack_i := i - 1
  971. state := after_delimiter_state
  972. else accumulator.append_character(ch)
  973. end
  974. when after_delimiter_state then
  975. if ch.is_equal(delimeter) then
  976. accumulator.append_character(ch)
  977. state := normal_state
  978. elseif ch.is_equal(opening_brace) then
  979. index := 0
  980. state := after_brace_state
  981. else
  982. i := backtrack_i
  983. state := always_print_state
  984. end
  985. when after_brace_state then
  986. if ch.is_decimal_digit then
  987. index := 10*index + ch.decimal_value
  988. elseif ch.is_equal(closing_brace) and then index = an_index then
  989. accumulator := "" -- newly allocated empty string
  990. Result := Result | a_value | accumulator
  991. state := normal_state
  992. else
  993. i := backtrack_i
  994. state := always_print_state
  995. end
  996. end
  997. i := i + 1
  998. end
  999. check
  1000. i >= 0
  1001. end
  1002. if state > normal_state then
  1003. i := backtrack_i + 1
  1004. state := always_print_state
  1005. end
  1006. end
  1007. ensure
  1008. definition: has_substring("#("+an_index.out+")") implies Result.has_substring(a_value) and not Result.has_substring("#("+an_index.out+")")
  1009. substitution_not_made: not has_substring("#("+an_index.out+")") implies Current.is_equal(Result)
  1010. end
  1011. infix "#" (a_value: ABSTRACT_STRING): ABSTRACT_STRING
  1012. -- A copy of Current with a placeholder "#(n)" is replaced with the content of `a_value'. A chain of # queries will progressively replace placeholder 1, 2 ...
  1013. --
  1014. -- For example a_string#"foo"#"bar"#"maman" is equivalent to a_string.arg(1,"foo").arg(2,"bar").arg(3,"maman")
  1015. --
  1016. -- See also `arg'.
  1017. do
  1018. create {PARTIALLY_FILLED_STRING} Result.from_string_and_arg(Current, a_value)
  1019. end
  1020. feature {ANY} -- Case conversion
  1021. as_lower: STRING
  1022. -- New object with all letters in lower case.
  1023. --
  1024. -- See also `as_upper', `to_lower', `to_upper'.
  1025. do
  1026. create Result.make_from_string(Current)
  1027. Result.to_lower
  1028. end
  1029. as_upper: STRING
  1030. -- New object with all letters in upper case.
  1031. --
  1032. -- See also `as_lower', `to_upper', `to_lower'.
  1033. do
  1034. create Result.make_from_string(Current)
  1035. Result.to_upper
  1036. end
  1037. feature {ANY} -- Printing:
  1038. out_in_tagged_out_memory
  1039. do
  1040. tagged_out_memory.append(Current)
  1041. end
  1042. fill_tagged_out_memory
  1043. deferred
  1044. end
  1045. feature {ANY} -- String replacing
  1046. replacing (an_old, a_new: ABSTRACT_STRING): STRING
  1047. -- Current with all occurrences of `an_old' string replaced with `a_new'.
  1048. require
  1049. not an_old.is_empty
  1050. a_new /= Void
  1051. do
  1052. create Result.with_capacity(count)
  1053. replacing_in(an_old, a_new, Result)
  1054. ensure
  1055. Result /= Current
  1056. not Result.valid_index(Result.first_substring_index(an_old))
  1057. Result.first_substring_index(a_new) = first_substring_index(an_old) --| **** TODO to be improved
  1058. end
  1059. replacing_in (an_old, a_new: ABSTRACT_STRING; buffer: STRING)
  1060. -- Current with all occurrences of `an_old' string replaced with `a_new' in `buffer'.
  1061. require
  1062. not an_old.is_empty
  1063. a_new /= Void
  1064. buffer /= Current
  1065. local
  1066. cut_from, oldsize, i: INTEGER
  1067. do
  1068. i := first_substring_index(an_old)
  1069. oldsize := an_old.count
  1070. from
  1071. cut_from := lower
  1072. until
  1073. not valid_index(i)
  1074. loop
  1075. buffer.append_substring(Current, cut_from, i - 1)
  1076. buffer.append(a_new)
  1077. cut_from := i + oldsize
  1078. i := substring_index(an_old, i + oldsize)
  1079. end
  1080. buffer.append_substring(Current, cut_from, upper)
  1081. ensure
  1082. not buffer.valid_index(buffer.substring_index(an_old, old (buffer.upper + buffer.lower)))
  1083. buffer.substring_index(a_new, old (buffer.upper + buffer.lower)) = old buffer.upper + first_substring_index(an_old) --| **** TODO to be improved
  1084. end
  1085. feature {ANY} -- Other features:
  1086. first: CHARACTER
  1087. -- Access to the very `first' character.
  1088. --
  1089. -- See also `last', `item'.
  1090. deferred
  1091. end
  1092. last: CHARACTER
  1093. -- Access to the very `last' character.
  1094. --
  1095. -- See also `first', `item'.
  1096. deferred
  1097. end
  1098. substring (start_index, end_index: INTEGER): like Current
  1099. -- New string consisting of items [`start_index'.. `end_index'].
  1100. --
  1101. -- See also `substring_index' and `copy_substring' to save memory.
  1102. require
  1103. valid_start_index: lower <= start_index
  1104. valid_end_index: end_index <= upper
  1105. meaningful_interval: start_index <= end_index + 1
  1106. deferred
  1107. ensure
  1108. substring_count: Result.count = end_index - start_index + 1
  1109. end
  1110. substring_index (other: ABSTRACT_STRING; start_index: INTEGER): INTEGER
  1111. -- Position of first occurrence of `other' at or after `start_index'.
  1112. -- If there is no occurrence Result will be an invalid index, usually 0 when lower is 1.
  1113. --
  1114. -- See also `substring', `first_substring_index'.
  1115. require
  1116. other_not_void: other /= Void
  1117. valid_start_index: start_index >= lower and start_index <= upper + 1
  1118. local
  1119. i, s: INTEGER
  1120. do
  1121. from
  1122. s := start_index
  1123. until
  1124. Result /= 0 or else s - lower + other.upper > upper
  1125. loop
  1126. from
  1127. i := other.lower
  1128. until
  1129. i > other.upper or else item(s + i - other.lower) /= other.item(i)
  1130. loop
  1131. i := i + 1
  1132. end
  1133. if i > other.upper then
  1134. Result := s
  1135. else
  1136. s := s + 1
  1137. end
  1138. end
  1139. end
  1140. first_substring_index (other: ABSTRACT_STRING): INTEGER
  1141. -- Position of first occurrence of `other' at or after 1, 0 if none.
  1142. --
  1143. -- See also `substring_index'.
  1144. require
  1145. other_not_void: other /= Void
  1146. do
  1147. Result := substring_index(other, lower)
  1148. ensure
  1149. definition: Result = substring_index(other, lower)
  1150. end
  1151. feature {ANY} -- Splitting a STRING:
  1152. split: ARRAY[STRING]
  1153. -- Split the string into an array of words. Uses `is_separator' of
  1154. -- CHARACTER to find words. Gives Void or a non empty array.
  1155. --
  1156. -- See also `split_in'.
  1157. do
  1158. if count > 0 then
  1159. split_buffer.clear_count
  1160. split_in(split_buffer)
  1161. if not split_buffer.is_empty then
  1162. Result := split_buffer.twin
  1163. end
  1164. end
  1165. ensure
  1166. Result /= Void implies not Result.is_empty
  1167. end
  1168. split_in (words: COLLECTION[STRING])
  1169. -- Same jobs as `split' but result is appended in `words'.
  1170. --
  1171. -- See also `split'.
  1172. require
  1173. words /= Void
  1174. local
  1175. state, i: INTEGER; c: CHARACTER
  1176. do
  1177. -- state = 0: waiting next word.
  1178. -- state = 1: inside a new word.
  1179. if count > 0 then
  1180. from
  1181. i := lower
  1182. until
  1183. i > count
  1184. loop
  1185. c := item(i)
  1186. if state = 0 then
  1187. if not c.is_separator then
  1188. string_buffer.clear_count
  1189. string_buffer.add_last(c)
  1190. state := 1
  1191. end
  1192. else
  1193. if not c.is_separator then
  1194. string_buffer.add_last(c)
  1195. else
  1196. words.add_last(string_buffer.twin)
  1197. state := 0
  1198. end
  1199. end
  1200. i := i + 1
  1201. end
  1202. if state = 1 then
  1203. words.add_last(string_buffer.twin)
  1204. end
  1205. end
  1206. ensure
  1207. words.count >= old words.count
  1208. end
  1209. feature {ANY} -- Other features:
  1210. new_iterator: ITERATOR[CHARACTER]
  1211. do
  1212. create {ITERATOR_ON_STRING} Result.make(Current)
  1213. end
  1214. intern: FIXED_STRING
  1215. -- A shared version of this string.
  1216. deferred
  1217. ensure
  1218. Result /= Void
  1219. Result.is_equal(Current)
  1220. Result.is_interned
  1221. interned.fast_has(Result.hash_code) and then interned.fast_reference_at(Result.hash_code).fast_has(Result)
  1222. end
  1223. feature {ANY} -- Interfacing with C string:
  1224. to_external: POINTER
  1225. -- The address of a memory region containing the text of Current, useful to interact with the C language.
  1226. -- A NATIVELY_STORED_STRING implementation usually gives direct access
  1227. -- to its internal `storage' (may be dangerous).
  1228. -- Other non-natively stored heirs provide access to an Eiffel-owned
  1229. -- buffer containing a copy of its content.
  1230. -- To be compatible with C, a null character is added at the end
  1231. -- of the internal `storage'. This extra null character is not
  1232. -- part of the Eiffel STRING.
  1233. deferred
  1234. ensure
  1235. -- TODO: generalize this postcondition
  1236. -- (is_empty or else storage.item(count) /= '%U') implies (capacity > count and then storage.item(count) = '%U')
  1237. count = old count
  1238. Result.is_not_null
  1239. end
  1240. feature {ANY} -- Other features here for ELKS compatibility:
  1241. same_string (other: ABSTRACT_STRING): BOOLEAN
  1242. -- (Here for ELKS compatibility.)
  1243. -- Do `Current' and `other' have the same character sequence?
  1244. -- Useful in proper descendants of STRING.
  1245. require
  1246. other_not_void: other /= Void
  1247. do
  1248. Result := string.is_equal(other.string)
  1249. end
  1250. string: STRING
  1251. -- (Here for ELKS compatibility.)
  1252. -- New STRING having the same character sequence as `Current'.
  1253. -- Useful in proper descendants of STRING.
  1254. do
  1255. create Result.make_from_string(Current)
  1256. end
  1257. feature {}
  1258. string_buffer: STRING
  1259. -- Private, temporary once buffer.
  1260. once
  1261. create Result.make(256)
  1262. end
  1263. split_buffer: ARRAY[STRING]
  1264. once
  1265. create Result.with_capacity(4, 1)
  1266. end
  1267. computed_hash_code: INTEGER
  1268. local
  1269. i: INTEGER
  1270. do
  1271. from
  1272. i := lower
  1273. until
  1274. i > upper
  1275. loop
  1276. Result := {INTEGER 5} #* Result #+ item(i).code
  1277. i := i + 1
  1278. end
  1279. if Result < 0 then
  1280. Result := ~Result
  1281. end
  1282. end
  1283. interned: HASHED_DICTIONARY[FAST_ARRAY[FIXED_STRING], INTEGER]
  1284. -- Key: `hash_code'
  1285. -- Item: interned string
  1286. once
  1287. create Result.make
  1288. end
  1289. feature {STRING_HANDLER}
  1290. copy_slice_to_native (start_index, end_index: INTEGER; target: NATIVE_ARRAY[CHARACTER]; target_offset: INTEGER)
  1291. require
  1292. start_index >= lower
  1293. end_index <= upper
  1294. start_index <= end_index
  1295. local
  1296. i, j: INTEGER
  1297. do
  1298. from
  1299. i := start_index
  1300. j := 0
  1301. until
  1302. i > end_index
  1303. loop
  1304. target.put(item(i), target_offset + j)
  1305. i := i + 1
  1306. j := j + 1
  1307. end
  1308. end
  1309. feature {} -- The states of the finite state automaton used in `arg' feature
  1310. always_print_state: INTEGER -1
  1311. normal_state: INTEGER 0
  1312. after_delimiter_state: INTEGER 1
  1313. after_brace_state: INTEGER 2
  1314. -- Please note that we picked the same values used in MESSAGE_FORMATTER. It may also be written like
  1315. -- "always_print_state, normal_state, after_delimiter_state, after_brace_state: INTEGER is unique"
  1316. -- but I'm not sure that the compiler will actually choose sequential
  1317. -- values necessary in the last if tense in the arg query
  1318. feature {}
  1319. debug_string: STRING
  1320. -- only used to display the content of the FIXED_STRING in the trace stack
  1321. invariant
  1322. 0 <= count
  1323. lower = 1
  1324. end -- class ABSTRACT_STRING
  1325. --
  1326. -- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
  1327. --
  1328. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  1329. -- of this software and associated documentation files (the "Software"), to deal
  1330. -- in the Software without restriction, including without limitation the rights
  1331. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1332. -- copies of the Software, and to permit persons to whom the Software is
  1333. -- furnished to do so, subject to the following conditions:
  1334. --
  1335. -- The above copyright notice and this permission notice shall be included in
  1336. -- all copies or substantial portions of the Software.
  1337. --
  1338. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1339. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1340. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1341. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1342. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1343. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  1344. -- THE SOFTWARE.