-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

-------------------------------------------------------------------------------
--                                                                           --
-- SPARK.Ada.Strings.Unbounded                                               --
--                                                                           --
-- Description                                                               --
--   This is a binding to package Ada.Strings.Unbounded                      --
--                                                                           --
-- Language                                                                  --
--   Specification : SPARK                                                   --
--   Private Part  : Ada                                                     --
--   Body          : Ada 2005                                                --
--                                                                           --
-- Runtime Requirements and Dependencies                                     --
--   Full Ada Runtime                                                        --
--                                                                           --
-- Verification                                                              --
--   N/A                                                                     --
--                                                                           --
-- Exceptions                                                                --
--   Ada.Strings.Index_Error (Guarded)                                       --
--   Ada.Strings.Pattern_Error (Guarded)                                     --
--                                                                           --
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
--
--  A few subprograms, in particular To_String, cannot currently be
--  SPARK, you will find them in
--  SPARK.Ada.Strings.Unbounded.Not_SPARK.
--
-------------------------------------------------------------------------------

with Ada.Strings.Unbounded;
with SPARK.Ada.Strings.Maps;

--# inherit SPARK.Ada.Strings.Maps;

package SPARK.Ada.Strings.Unbounded is

   type Unbounded_String is private;

   Null_Unbounded_String : constant Unbounded_String;

   --  function Length (Source : Unbounded_String) return Natural;
   function Get_Length (Source : Unbounded_String) return Natural;

   function Get_Null_Unbounded_String return Unbounded_String;
   --# return S => Get_Length (S) = 0 and S = Null_Unbounded_String;

   --  function Element
   --    (Source : Unbounded_String;
   --     Index  : Positive) return Character;
   function Get_Element
     (Source : Unbounded_String;
      Index  : Positive) return Character;
   --# pre Index <= Get_Length (Source);

   --------------------------------------------------------
   -- Conversion, Concatenation, and Selection Functions --
   --------------------------------------------------------

   --  function To_Unbounded_String
   --    (Source : String)  return Unbounded_String;
   function String_To_Unbounded_String
     (Source : String) return Unbounded_String;
   --# return X => Get_Length (X) = Source'Length;

   --  Return an unbounded string initialized with spaces.
   --  function To_Unbounded_String
   --    (Length : Natural) return Unbounded_String;
   function Length_To_Unbounded_String
     (Length : Natural) return Unbounded_String;
   --# return X => Get_Length (X) = Length;

   --  Set_Unbounded_String is only defined in Ada 2005
   procedure Set_Unbounded_String
     (Target :    out Unbounded_String;
      Source : in     String);
   --# derives Target from Source;
   --# post Get_Length (Target) = Source'Length;

   --  procedure Append
   --    (Source   : in out Unbounded_String;
   --     New_Item : in     Unbounded_String);
   procedure Append_Unbounded_String
     (Source   : in out Unbounded_String;
      New_Item : in     Unbounded_String);
   --# derives Source from *,
   --#                     New_Item;
   --# pre Get_Length (Source) + Get_Length (New_Item) <= Natural'Last;
   --# post Get_Length (Source) = Get_Length (Source~) + Get_Length (New_Item);

   --  procedure Append
   --    (Source   : in out Unbounded_String;
   --     New_Item : in     String);
   procedure Append_String
     (Source   : in out Unbounded_String;
      New_Item : in     String);
   --# derives Source from *,
   --#                     New_Item;
   --# pre Get_Length (Source) + New_Item'Length <= Natural'Last;
   --# post Get_Length (Source) = Get_Length (Source~) + New_Item'Length;

   --  procedure Append
   --    (Source   : in out Unbounded_String;
   --     New_Item : in     Character);
   procedure Append_Char
     (Source   : in out Unbounded_String;
      New_Item : in     Character);
   --# derives Source from *,
   --#                     New_Item;
   --# pre Get_Length (Source) < Natural'Last;
   --# post Get_Length (Source) = Get_Length (Source~) + 1;

   --  function "&"
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Unbounded_String;
   function Concat_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Unbounded_String;
   --# pre Get_Length (Left) + Get_Length (Right) <= Natural'Last;
   --# return X => Get_Length (X) = Get_Length (Left) + Get_Length (Right);

   --  function "&"
   --    (Left  : Unbounded_String;
   --     Right : String) return Unbounded_String;
   function Concat_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Unbounded_String;
   --# pre Get_Length (Left) + Right'Length <= Natural'Last;
   --# return X => Get_Length (X) = Get_Length (Left) + Right'Length;

   --  function "&"
   --    (Left  : String;
   --     Right : Unbounded_String) return Unbounded_String;
   function Concat_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Unbounded_String;
   --# pre Left'Length + Get_Length (Right) <= Natural'Last;
   --# return X => Get_Length (X) = Left'Length + Get_Length (Right);

   --  function "&"
   --    (Left  : Unbounded_String;
   --     Right : Character) return Unbounded_String;
   function Concat_Unbounded_String_Char
     (Left  : Unbounded_String;
      Right : Character) return Unbounded_String;
   --# pre Get_Length (Left) < Natural'Last;
   --# return X => Get_Length (X) = Get_Length (Left) + 1;

   --  function "&"
   --    (Left  : Character;
   --     Right : Unbounded_String) return Unbounded_String;
   function Concat_Char_Unbounded_String
     (Left  : Character;
      Right : Unbounded_String) return Unbounded_String;
   --# pre Get_Length (Right) < Natural'Last;
   --# return X => Get_Length (X) = 1 + Get_Length (Right);

   procedure Replace_Element
     (Source : in out Unbounded_String;
      Index  : in     Positive;
      By     : in     Character);
   --# derives Source from *,
   --#                     By,
   --#                     Index;
   --# pre Index <= Get_Length (Source);
   --# post Get_Length (Source) = Get_Length (Source~);

   --  Unbounded_Slice is only defined in Ada 2005
   --  function Unbounded_Slice
   --    (Source : Unbounded_String;
   --     Low    : Positive;
   --     High   : Natural) return Unbounded_String;
   function Function_Unbounded_Slice
     (Source : Unbounded_String;
      Low    : Positive;
      High   : Natural) return Unbounded_String;
   --# pre Low <= Get_Length (Source) + 1 and High <= Get_Length (Source);
   --# return X => ((Low > High -> Get_Length (X) = 0) and
   --#                (Low <= High -> Get_Length (X) = (High - Low) + 1));

   --  Unbounded_Slice is only defined in Ada 2005
   --  procedure Unbounded_Slice
   --    (Source : in     Unbounded_String;
   --     Target :    out Unbounded_String;
   --     Low    : in     Positive;
   --     High   : in     Natural);
   procedure Procedure_Unbounded_Slice
     (Source : in     Unbounded_String;
      Target :    out Unbounded_String;
      Low    : in     Positive;
      High   : in     Natural);
   --# derives Target from High,
   --#                     Low,
   --#                     Source;
   --# pre Low <= Get_Length (Source) + 1 and High <= Get_Length (Source);
   --# post (Low > High -> Get_Length (Target) = 0) and
   --#   (Low <= High -> Get_Length (Target) = (High - Low) + 1);

   --  function "="
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Boolean;
   function Equal_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Boolean;
   --# return (Get_Length (Left) = Get_Length (Right)) and
   --#   (for all I in Natural range 1 .. Get_Length (Left) =>
   --#      (Get_Element (Left, I) = Get_Element (Right, I)));

   --  function "="
   --    (Left  : Unbounded_String;
   --     Right : String) return Boolean;
   function Equal_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Boolean;
   --# return (Get_Length (Left) = Right'Length) and
   --#   (for all I in Natural range 1 .. Right'Length =>
   --#      (Get_Element (Left, I) = Right (I)));

   --  function "="
   --    (Left  : String;
   --     Right : Unbounded_String) return Boolean;
   function Equal_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Boolean;
   --# return (Left'Length = Get_Length (Right)) and
   --#   (for all I in Natural range 1 .. Left'Length =>
   --#      (Left (I) = Get_Element (Right, I)));

   --  function "<"
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Boolean;
   function Less_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Boolean;

   --  function "<"
   --    (Left  : Unbounded_String;
   --     Right : String) return Boolean;
   function Less_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Boolean;

   --  function "<"
   --    (Left  : String;
   --     Right : Unbounded_String) return Boolean;
   function Less_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Boolean;

   --  function "<="
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Boolean;
   function Less_Equal_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Boolean;

   --  function "<="
   --    (Left  : Unbounded_String;
   --     Right : String) return Boolean;
   function Less_Equal_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Boolean;

   --  function "<="
   --    (Left  : String;
   --     Right : Unbounded_String) return Boolean;
   function Less_Equal_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Boolean;

   --  function ">"
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Boolean;
   function Greater_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Boolean;

   --  function ">"
   --    (Left  : Unbounded_String;
   --     Right : String) return Boolean;
   function Greater_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Boolean;

   --  function ">"
   --    (Left  : String;
   --     Right : Unbounded_String) return Boolean;
   function Greater_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Boolean;

   --  function ">="
   --    (Left  : Unbounded_String;
   --     Right : Unbounded_String) return Boolean;
   function Greater_Equal_Unbounded_String_Unbounded_String
     (Left  : Unbounded_String;
      Right : Unbounded_String) return Boolean;

   --  function ">="
   --    (Left  : Unbounded_String;
   --     Right : String) return Boolean;
   function Greater_Equal_Unbounded_String_String
     (Left  : Unbounded_String;
      Right : String) return Boolean;

   --  function ">="
   --    (Left  : String;
   --     Right : Unbounded_String) return Boolean;
   function Greater_Equal_String_Unbounded_String
     (Left  : String;
      Right : Unbounded_String) return Boolean;

   ------------------------
   -- Search Subprograms --
   ------------------------

   --  function Index
   --    (Source  : Unbounded_String;
   --     Pattern : String;
   --     Going   : Direction := Forward;
   --     Mapping : Maps.Character_Mapping := Maps.Identity) return Natural;
   function Index_Pattern
     (Source  : Unbounded_String;
      Pattern : String;
      Going   : Strings.Direction;
      Mapping : Maps.Character_Mapping) return Natural;
   --# pre Pattern'Length > 0;
   --# return X => (X <= (Get_Length (Source) - Pattern'Length) + 1);

   --  function Index
   --    (Source : Unbounded_String;
   --     Set    : Maps.Character_Set;
   --     Test   : Membership := Inside;
   --     Going  : Direction  := Forward) return Natural;
   function Index_Set
     (Source  : Unbounded_String;
      Arg_Set : Maps.Character_Set;
      Test    : Strings.Membership;
      Going   : Strings.Direction) return Natural;
   --# return X => (X <= Get_Length (Source));

   --  Index is only defined in Ada 2005
   --  function Index
   --    (Source  : Unbounded_String;
   --     Pattern : String;
   --     From    : Positive;
   --     Going   : Direction := Forward;
   --     Mapping : Maps.Character_Mapping := Maps.Identity) return Natural;
   function Index_Pattern_From
     (Source   : Unbounded_String;
      Pattern  : String;
      Arg_From : Positive;
      Going    : Strings.Direction;
      Mapping  : Maps.Character_Mapping) return Natural;
   --# pre Pattern'Length > 0 and
   --#   (Going = Strings.Direction_Backward ->
   --#      Arg_From <= Get_Length (Source));
   --# return X =>
   --#   (X = 0 or
   --#      ((Going = Strings.Direction_Forward ->
   --#          X in Arg_From .. ((Get_Length (Source) - Pattern'Length) + 1))
   --#       and
   --#         (Going = Strings.Direction_Backward ->
   --#            X in 1 .. (Arg_From - Pattern'Length) + 1)));

   --  Index is only defined in Ada 2005
   --  function Index
   --    (Source  : Unbounded_String;
   --     Set     : Maps.Character_Set;
   --     From    : Positive;
   --     Test    : Membership := Inside;
   --     Going   : Direction := Forward) return Natural;
   function Index_Set_From
     (Source   : Unbounded_String;
      Arg_Set  : Maps.Character_Set;
      Arg_From : Positive;
      Test     : Strings.Membership;
      Going    : Strings.Direction) return Natural;
   --# pre Arg_From <= Get_Length (Source);
   --# return X =>
   --#   (X = 0 or
   --#      ((Going = Strings.Direction_Forward  ->
   --#          X in Arg_From .. Get_Length (Source)) and
   --#         (Going = Strings.Direction_Backward -> X in 1 .. Arg_From)));

   --  Index is only defined in Ada 2005
   --  function Index_Non_Blank
   --    (Source : Unbounded_String;
   --     Going  : Direction := Forward) return Natural;
   function Index_Non_Blank
     (Source : Unbounded_String;
      Going  : Strings.Direction) return Natural;
   --# return X => (X <= Get_Length (Source));

   --  Index is only defined in Ada 2005
   --  function Index_Non_Blank
   --    (Source : Unbounded_String;
   --     From   : Positive;
   --     Going  : Direction := Forward) return Natural;
   function Index_Non_Blank_From
     (Source   : Unbounded_String;
      Arg_From : Positive;
      Going    : Strings.Direction) return Natural;
   --# pre Going = Strings.Direction_Backward ->
   --#   Arg_From <= Get_Length (Source);
   --# return X =>
   --#   (X = 0 or
   --#      ((Going = Strings.Direction_Forward  ->
   --#          X in Arg_From .. Get_Length (Source)) and
   --#         (Going = Strings.Direction_Backward -> X in 1 .. Arg_From)));

   --  function Count
   --    (Source  : Unbounded_String;
   --     Pattern : String;
   --     Mapping : Maps.Character_Mapping := Maps.Identity) return Natural;
   function Count_Pattern
     (Source  : Unbounded_String;
      Pattern : String;
      Mapping : Maps.Character_Mapping) return Natural;
   --# pre Pattern'Length > 0;
   --# return X => (X <= Get_Length (Source) / Pattern'Length);

   --  function Count
   --    (Source : Unbounded_String;
   --     Set    : Maps.Character_Set) return Natural;
   function Count_Set
     (Source  : Unbounded_String;
      Arg_Set : Maps.Character_Set) return Natural;
   --# return X => (X <= Get_Length (Source));

   --  procedure Find_Token
   --    (Source : in     Unbounded_String;
   --     Set    : in     Maps.Character_Set;
   --     Test   : in     Membership;
   --     First  :    out Positive;
   --     Last   :    out Natural);
   procedure Find_Token
     (Source    : in     Unbounded_String;
      Arg_Set   : in     Maps.Character_Set;
      Test      : in     Strings.Membership;
      Arg_First :    out Positive;
      Arg_Last  :    out Natural);
   --# derives Arg_First,
   --#         Arg_Last  from Arg_Set,
   --#                        Source,
   --#                        Test;
   --# post (Arg_First <= Get_Length (Source))
   --#   and (Arg_Last <= Get_Length (Source))
   --#   and ((Arg_First <= Arg_Last) or (Arg_First = 1 and Arg_Last = 0))
   --#   and (for all I in Natural range Arg_First .. Arg_Last =>
   --#          (Maps.Is_In (Get_Element (Source, I), Arg_Set)));

   ------------------------------------
   -- String Translation Subprograms --
   ------------------------------------

   --  function Translate
   --    (Source  : Unbounded_String;
   --     Mapping : Maps.Character_Mapping) return Unbounded_String;
   function Function_Translate
     (Source  : Unbounded_String;
      Mapping : Maps.Character_Mapping) return Unbounded_String;
   --# return X => (Get_Length (X) = Get_Length (Source));

   --  procedure Translate
   --    (Source  : in out Unbounded_String;
   --     Mapping : in     Maps.Character_Mapping);
   procedure Procedure_Translate
     (Source  : in out Unbounded_String;
      Mapping : in     Maps.Character_Mapping);
   --# derives Source from *,
   --#                     Mapping;
   --# post Get_Length (Source) = Get_Length (Source~);

   ---------------------------------------
   -- String Transformation Subprograms --
   ---------------------------------------

   --  The two Replace_Slice implementations have very difficult
   --  corner cases. We present an implementation that has slightly
   --  stronger pre- and postconditions in order to make proof of
   --  absence of RTE still possible but simplify writing down the
   --  postconditions.

   --  Furthermore, note that a bug in the Ada standard library
   --  provided by GNAT up to 6.4.1 requires the extra precondition:
   --     High <= Get_Length (Source) + 1

   --  We feel that this slightly stronger pre-condition does not
   --  invalidate sensible uses of this function.

   --  function Replace_Slice
   --    (Source : Unbounded_String;
   --     Low    : Positive;
   --     High   : Natural;
   --     By     : String) return Unbounded_String;
   function Function_Replace_Slice
     (Source : Unbounded_String;
      Low    : Positive;
      High   : Natural;
      By     : String) return Unbounded_String;
   --# pre Low <= Get_Length (Source) + 1 and High <= Get_Length (Source) + 1
   --#   and By'Length + Get_Length (Source) <= Natural'Last;
   --# return X => ((Low <= High ->
   --#                 Get_Length (X) = By'Length + Get_Length (Source) + Low -
   --#                 Natural'Min (High, Get_Length (Source)) - 1) and
   --#                (Low > High ->
   --#                   Get_Length (X) = By'Length + Get_Length (Source)));

   --  procedure Replace_Slice
   --    (Source : in out Unbounded_String;
   --     Low    : in     Positive;
   --     High   : in     Natural;
   --     By     : in     String);
   procedure Procedure_Replace_Slice
     (Source : in out Unbounded_String;
      Low    : in     Positive;
      High   : in     Natural;
      By     : in     String);
   --# derives Source from *,
   --#                     By,
   --#                     High,
   --#                     Low;
   --# pre Low <= Get_Length (Source) + 1 and High <= Get_Length (Source) + 1
   --#   and By'Length + Get_Length (Source) <= Natural'Last;
   --# post (Low <= High ->
   --#         Get_Length (Source) = By'Length + Get_Length (Source~) + Low -
   --#         Natural'Min (High, Get_Length (Source~)) - 1) and
   --#   (Low > High ->
   --#      Get_Length (Source) = By'Length + Get_Length (Source~));
   --#

   --  function Insert
   --    (Source   : Unbounded_String;
   --     Before   : Positive;
   --     New_Item : String) return Unbounded_String;
   function Function_Insert
     (Source   : Unbounded_String;
      Before   : Positive;
      New_Item : String) return Unbounded_String;
   --# pre Before <= Get_Length (Source) + 1 and
   --#   Get_Length (Source) + New_Item'Length <= Natural'Last;
   --# return X => (Get_Length (X) = Get_Length (Source) + New_Item'Length);

   --  procedure Insert
   --    (Source   : in out Unbounded_String;
   --     Before   : in     Positive;
   --     New_Item : in     String);
   procedure Procedure_Insert
     (Source   : in out Unbounded_String;
      Before   : in     Positive;
      New_Item : in     String);
   --# derives Source from *,
   --#                     Before,
   --#                     New_Item;
   --# pre Before <= Get_Length (Source) + 1 and
   --#   Get_Length (Source) + New_Item'Length <= Natural'Last;
   --# post Get_Length (Source) = Get_Length (Source~) + New_Item'Length;

   --  function Overwrite
   --    (Source   : Unbounded_String;
   --     Position : Positive;
   --     New_Item : String) return Unbounded_String;
   function Function_Overwrite
     (Source   : Unbounded_String;
      Position : Positive;
      New_Item : String) return Unbounded_String;
   --# pre Position <= Get_Length (Source) + 1 and
   --#   Position + New_Item'Length - 1 <= Natural'Last;
   --# return X => (Get_Length (X) = Natural'Max
   --#                (Get_Length (Source), Position + New_Item'Length - 1));

   --  procedure Overwrite
   --    (Source   : in out Unbounded_String;
   --     Position : in     Positive;
   --     New_Item : in     String);
   procedure Procedure_Overwrite
     (Source   : in out Unbounded_String;
      Position : in     Positive;
      New_Item : in     String);
   --# derives Source from *,
   --#                     New_Item,
   --#                     Position;
   --# pre Position <= Get_Length (Source) + 1 and
   --#   Position + New_Item'Length - 1 <= Natural'Last;
   --# post Get_Length (Source) = Natural'Max
   --#   (Get_Length (Source~), Position + New_Item'Length - 1);

   --  The last part of the return annotation is not strictly
   --  necessary, but may make some RTE-freedom proofs easier.
   --  function Delete
   --    (Source  : Unbounded_String;
   --     From    : Positive;
   --     Through : Natural) return Unbounded_String;
   function Function_Delete
     (Source   : Unbounded_String;
      Arg_From : Positive;
      Through  : Natural) return Unbounded_String;
   --# pre Through <= Get_Length (Source);
   --# return X =>
   --#   ((Arg_From > Through -> Get_Length (X) = 0) and
   --#      (Arg_From <= Through ->
   --#         Get_Length (X) = Get_Length (Source) -
   --#         (Through - Arg_From + 1)) and
   --#      (Get_Length (X) <= Get_Length (Source)));

   --  The last part of the postcondition is not strictly necessary,
   --  but may make some RTE-freedom proofs easier.
   --  procedure Delete
   --    (Source  : in out Unbounded_String;
   --     From    : in     Positive;
   --     Through : in     Natural);
   procedure Procedure_Delete
     (Source   : in out Unbounded_String;
      Arg_From : in     Positive;
      Through  : in     Natural);
   --# derives Source from *,
   --#                     Arg_From,
   --#                     Through;
   --# pre Through <= Get_Length (Source);
   --# post ((Arg_From > Through -> Get_Length (Source) = 0) and
   --#         (Arg_From <= Through ->
   --#            Get_Length (Source) = Get_Length (Source~) -
   --#            (Through - Arg_From + 1)) and
   --#         (Get_Length (Source) <= Get_Length (Source~)));

   --  function Trim
   --    (Source : Unbounded_String;
   --     Side   : Trim_End) return Unbounded_String;
   function Function_Trim_Side
     (Source : Unbounded_String;
      Side   : Strings.Trim_End) return Unbounded_String;
   --# return X => (Get_Length (X) <= Get_Length (Source));

   --  procedure Trim
   --    (Source : in out Unbounded_String;
   --     Side   : in     Trim_End);
   procedure Procedure_Trim_Side
     (Source : in out Unbounded_String;
      Side   : in     Strings.Trim_End);
   --# derives Source from *,
   --#                     Side;
   --# post Get_Length (Source) <= Get_Length (Source~);

   --  function Trim
   --    (Source : Unbounded_String;
   --     Left   : Maps.Character_Set;
   --     Right  : Maps.Character_Set) return Unbounded_String;
   function Function_Trim_Character_Set
     (Source : Unbounded_String;
      Left   : Maps.Character_Set;
      Right  : Maps.Character_Set) return Unbounded_String;
   --# return X => (Get_Length (X) <= Get_Length (Source));

   --  procedure Trim
   --    (Source : in out Unbounded_String;
   --     Left   : in     Maps.Character_Set;
   --     Right  : in     Maps.Character_Set);
   procedure Procedure_Trim_Character_Set
     (Source : in out Unbounded_String;
      Left   : in     Maps.Character_Set;
      Right  : in     Maps.Character_Set);
   --# derives Source from *,
   --#                     Left,
   --#                     Right;
   --# post Get_Length (Source) <= Get_Length (Source~);

   --  function Head
   --    (Source : Unbounded_String;
   --     Count  : Natural;
   --     Pad    : Character := Space) return Unbounded_String;
   function Function_Head
     (Source : Unbounded_String;
      Count  : Natural;
      Pad    : Character) return Unbounded_String;
   --# return X => (Get_Length (X) = Count);

   --  procedure Head
   --    (Source : in out Unbounded_String;
   --     Count  : in     Natural;
   --     Pad    : in     Character := Space);
   procedure Procedure_Head
     (Source : in out Unbounded_String;
      Count  : in     Natural;
      Pad    : in     Character);
   --# derives Source from *,
   --#                     Count,
   --#                     Pad;
   --# post Get_Length (Source) = Count;

   --  function Tail
   --    (Source : Unbounded_String;
   --     Count  : Natural;
   --     Pad    : Character := Space) return Unbounded_String;
   function Function_Tail
     (Source : Unbounded_String;
      Count  : Natural;
      Pad    : Character) return Unbounded_String;
   --# return X => (Get_Length (X) = Count);

   --  procedure Tail
   --    (Source : in out Unbounded_String;
   --     Count  : in     Natural;
   --     Pad    : in     Character := Space);
   procedure Procedure_Tail
     (Source : in out Unbounded_String;
      Count  : in     Natural;
      Pad    : in     Character);
   --# derives Source from *,
   --#                     Count,
   --#                     Pad;
   --# post Get_Length (Source) = Count;

   --  function "*"
   --    (Left  : Natural;
   --     Right : Character) return Unbounded_String;
   function Times_Char
     (Left  : Natural;
      Right : Character) return Unbounded_String;
   --# return X => (Get_Length (X) = Left);

   --  function "*"
   --    (Left  : Natural;
   --     Right : String) return Unbounded_String;
   function Times_String
     (Left  : Natural;
      Right : String) return Unbounded_String;
   --# pre Left * Right'Length <= Natural'Last;
   --# return X => (Get_Length (X) = Left * Right'Length);

   --  function "*"
   --    (Left  : Natural;
   --     Right : Unbounded_String) return Unbounded_String;
   function Times_Unbounded_String
     (Left  : Natural;
      Right : Unbounded_String) return Unbounded_String;
   --# pre Left * Get_Length (Right) <= Natural'Last;
   --# return X => (Get_Length (X) = Left * Get_Length (Right));


private
   --# hide SPARK.Ada.Strings.Unbounded;
   type Unbounded_String is
     new Standard.Ada.Strings.Unbounded.Unbounded_String;

   Null_Unbounded_String : constant Unbounded_String :=
     Unbounded_String (Standard.Ada.Strings.Unbounded.Null_Unbounded_String);

end SPARK.Ada.Strings.Unbounded;
