File : units.ads



--  Generic package to deal with dimensional values.
--  The user should be able to compute with the values with respect to
--  the units. Dimension errors (on addition) should be statically catched.

generic
   type Accuracy is digits <>;
package Units is
   --  Unit is a composite of a numeric and a unit dimension.
   type Unit is private;
   
   --  Dimension counts how much of the units are included.
   --  http://physics.nist.gov/cuu/Units/units.html
   type Dimension is record
      length, time, mass, current, temperature, substance_amount,
        luminous_intensity : Integer;
   end record;
   
   --  The base system of the dimension space.
   dim_meter    : constant Dimension := (length             => 1, others => 0);
   dim_second   : constant Dimension := (time               => 1, others => 0);
   dim_kilogram : constant Dimension := (mass               => 1, others => 0);
   dim_ampere   : constant Dimension := (current            => 1, others => 0);
   dim_kelvin   : constant Dimension := (temperature        => 1, others => 0);
   dim_mol      : constant Dimension := (substance_amount   => 1, others => 0);
   dim_candela  : constant Dimension := (luminous_intensity => 1, others => 0);

   --  Negate, multiply, divide, expotentiate and output values.
   function "-" (a : Unit) return Unit;
   function "*" (a, b : Unit) return Unit;
   function "/" (a, b : Unit) return Unit;
   function "**" (a : Unit; b : Integer) return Unit;
   function To_String (a : Unit) return String;
   
   --  Multiply, divide, expotentiate and output Dimensions.
   function "*" (a, b : Dimension) return Dimension;
   function "/" (a, b : Dimension) return Dimension;
   function "**" (a : Dimension; b : Integer) return Dimension;
   function To_String (a : Dimension) return String;

   --  Possible prefixes for all units.
   --  http://physics.nist.gov/cuu/Units/prefixes.html
   type Prefix is (yocto, zepto, atto, femto, pico, nano, micro, milli, centi,
     deci, deka, hecto, kilo, kibi, mega, mebi, giga, gibi, tera, tebi, peta,
     pebi, exa, exbi, zetta, yotta);
   
   --  In order to catch dimension errors statically and input new values,
   --  every point the the discrete dimension space may generate new types.
   generic
      dim : Dimension;
   package Special_Units is
      --  Such a dimensional value a given point is a pure numeric.
      type Special_Unit is private;
      
      --  Read in new values from extern.
      function "+" (v : Accuracy) return Special_Unit;
      function "*" (v : Accuracy; p : Prefix) return Special_Unit;
      
      --  Add and subctract values of the same dimension.
      function "+" (a, b : Special_Unit) return Special_Unit;
      function "-" (a, b : Special_Unit) return Special_Unit;
      
      --  Conversion between a generic unit and a special one.
      --  BUG! Converting from a Unit to a Special_Unit may raise an Error
      --  on runtime. Of course the compiler can be determine the dimension
      --  on compile time and may reject the conversion, but ...
      function "+" (a : Special_Unit) return Unit;
      Dimension_Error : exception;
      function "+" (a : Unit) return Special_Unit;
   private
      type Special_Unit is record
         value : Accuracy;
      end record;
   end Special_Units;

private
   type Unit is record
      value : Accuracy;
      dim   : Dimension;
   end record;
end Units;