// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) /// Стандартный модуль /// !! System unit unit PABCSystem; {$zerobasedstrings off} // Default Application type {$apptype console} {$reference '%GAC%\System.dll'} {$reference '%GAC%\mscorlib.dll'} {$reference '%GAC%\System.Core.dll'} {$reference '%GAC%\System.Numerics.dll'} interface uses System.Runtime.InteropServices, System.IO, System.Collections, System.Collections.Generic, System; //{{{doc: Начало секции стандартных констант для документации }}} const // ----------------------------------------------------- //>> Стандартные константы # Standard constants // ----------------------------------------------------- /// Максимальное значение типа shortint MaxShortInt = shortint.MaxValue; /// Максимальное значение типа byte MaxByte = byte.MaxValue; /// Максимальное значение типа smallint MaxSmallInt = smallint.MaxValue; /// Максимальное значение типа word MaxWord = word.MaxValue; /// Максимальное значение типа longword MaxLongWord = longword.MaxValue; /// Максимальное значение типа int64 MaxInt64 = int64.MaxValue; /// Максимальное значение типа uint64 MaxUInt64 = uint64.MaxValue; /// Максимальное значение типа double MaxDouble = real.MaxValue; /// Минимальное положительное значение типа double MinDouble = real.Epsilon; /// Максимальное значение типа real MaxReal = real.MaxValue; /// Минимальное положительное значение типа real MinReal = real.Epsilon; /// Максимальное значение типа single MaxSingle = single.MaxValue; /// Минимальное положительное значение типа single MinSingle = single.Epsilon; /// Максимальное значение типа integer MaxInt = integer.MaxValue; /// Константа Pi /// !! Pi constant Pi = 3.141592653589793; /// Константа E /// !! E constant E = 2.718281828459045; /// Константа перехода на новую строку /// !! The newline string defined for this environment. NewLine = System.Environment.NewLine; /// Константа - символы-разделители слов /// !! symbols - word delimiters AllDelimiters = ' <>=^`|~$№§!"#%&''()*,+-./:;?@[\]_{}«­·»'#9#10#13; //{{{--doc: Конец секции стандартных констант для документации }}} //Маркер того, что это системный модуль ///-- const END_OF_LINE_SYMBOL = #10; __IS_SYSTEM_MODULE = true; //{{{doc: Начало секции стандартных типов для документации }}} type // ----------------------------------------------------- //>> Стандартные типы # Standard types // ----------------------------------------------------- /// Базовый тип объектов Object = System.Object; /// Базовый тип исключений Exception = System.Exception; /// double = real double = System.Double; /// longint = integer longint = System.Int32; /// cardinal = longword cardinal = System.UInt32; /// Представляет 128-битное вещественное число /// !! Represents a decimal number decimal = System.Decimal; /// Представляет произвольно большое целое число BigInteger = System.Numerics.BigInteger; /// Представляет дату и время DateTime = System.DateTime; /// Представляет комплексное число Complex = System.Numerics.Complex; /// Представляет кортеж Tuple = System.Tuple; /// Представляет список на базе динамического массива List = System.Collections.Generic.List; /// Представляет базовый класс для реализации интерфейса IComparer Comparer = System.Collections.Generic.Comparer; /// Представляет базовый класс для реализации интерфейса IComparer IComparable = System.IComparable; /// Представляет множество значений, реализованное на базе хеш-таблицы HashSet = System.Collections.Generic.HashSet; /// Представляет множество значений, реализованное на базе бинарного дерева поиска SortedSet = System.Collections.Generic.SortedSet; /// Представляет ассоциативный массив (набор пар Ключ-Значение), реализованный на базе хеш-таблицы Dictionary = System.Collections.Generic.Dictionary; /// Представляет ассоциативный массив, реализованный на базе бинарного дерева поиска SortedDictionary = System.Collections.Generic.SortedDictionary; /// Представляет ассоциативный массив (набор пар ключ-значение), реализованный на базе динамического массива пар SortedList = System.Collections.Generic.SortedList; /// Представляет пару Ключ-Значение для ассоциативного массива KeyValuePair = System.Collections.Generic.KeyValuePair; /// Представляет двусвязный список LinkedList = System.Collections.Generic.LinkedList; /// Представляет узел двусвязного списка LinkedListNode = System.Collections.Generic.LinkedListNode; /// Представляет очередь - набор элементов, реализованных по принципу "первый вошел-первый вышел" Queue = System.Collections.Generic.Queue; /// Представляет стек - набор элементов, реализованных по принципу "последний вошел-первый вышел" Stack = System.Collections.Generic.Stack; /// Представляет интерфейс для коллекции ICollection = System.Collections.Generic.ICollection; /// Представляет интерфейс для сравнения двух элементов IComparer = System.Collections.Generic.IComparer; /// Представляет интерфейс для набора пар Ключ-Значение IDictionary = System.Collections.Generic.IDictionary; /// Представляет интерфейс, предоставляющий перечислитель для перебора элементов коллекции IEnumerable = System.Collections.Generic.IEnumerable; /// Представляет интерфейс для перебора элементов коллекции IEnumerator = System.Collections.Generic.IEnumerator; /// Представляет интерфейс для поддержки сравнения на равенство IEqualityComparer = System.Collections.Generic.IEqualityComparer; /// Представляет интерфейс для коллекции с доступом по индексу IList = System.Collections.Generic.IList; /// Представляет интерфейс для множества ISet = System.Collections.Generic.ISet; /// Представляет изменяемую строку символов StringBuilder = System.Text.StringBuilder; /// Представляет строку с эффективным изменением faststring = StringBuilder; /// Тип кодировки символов Encoding = System.Text.Encoding; /// Класс, управляющий консольным окном и консольным вводом-выводом Console = System.Console; /// Класс, управляющий сборкой мусора GC = System.GC; /// Представляет действие без параметров Action0 = System.Action; /// Представляет действие с одним параметром Action = System.Action; /// Представляет действие с двумя параметрами Action2 = System.Action; /// Представляет действие с тремя параметрами Action3 = System.Action; /// Представляет функцию без параметров Func0 = System.Func; /// Представляет функцию с одним параметром Func = System.Func; /// Представляет функцию с двумя параметрами Func2 = System.Func; /// Представляет функцию с тремя параметрами Func3 = System.Func; /// Представляет функцию с одним параметром целого типа, возвращающую целое IntFunc = Func; /// Представляет функцию с одним параметром вещественного типа, возвращающую вещественное RealFunc = Func; /// Представляет функцию с одним параметром строкового типа, возвращающую строку StringFunc = Func; /// Представляет функцию с одним параметром, возвращающую boolean Predicate = System.Predicate; /// Представляет функцию с двумя параметрами, возвращающую boolean Predicate2 = function(x1: T1; x2: T2): boolean; /// Представляет функцию с тремя параметрами, возвращающую boolean Predicate3 = function(x1: T1; x2: T2; x3: T3): boolean; /// Представляет регулярное выражение Regex = System.Text.RegularExpressions.Regex; /// Представляет результаты из отдельного совпадения регулярного выражения &Match = System.Text.RegularExpressions.&Match; /// Представляет метод, вызываемый при обнаружении совпадения в Regex.Replace MatchEvaluator = System.Text.RegularExpressions.MatchEvaluator; /// Представляет набор успешных совпадений регулярного выражения MatchCollection = System.Text.RegularExpressions.MatchCollection; /// Представляет параметры регулярного выражения RegexOptions = System.Text.RegularExpressions.RegexOptions; /// Представляет результаты из одной группы при выполнении Regex.Match RegexGroup = System.Text.RegularExpressions.Group; /// Представляет результаты из набора групп при выполнении Regex.Match RegexGroupCollection = System.Text.RegularExpressions.GroupCollection; /// Предоставляет методы для точного измерения затраченного времени Stopwatch = System.Diagnostics.Stopwatch; /// Преобразует значение одного базового типа к другому базовому типу Convert = System.Convert; /// Указывает на возможность сериализации класса Serializable = System.SerializableAttribute; /// Указывает, что поле сериализуемого класса не должно быть сериализовано NonSerialized = System.NonSerializedAttribute; /// Сведения для форматирования числовых значений NumberFormatInfo = System.Globalization.NumberFormatInfo; /// Представляет тип короткой строки фиксированной длины 255 символов ShortString = string[255]; // Атрибут для кеширования результатов функции CacheAttribute = class(System.Attribute) public constructor Create; begin end; end; //{{{--doc: Конец секции стандартных типов для документации }}} //------------------------------------------------------------------------------ //Pointers //------------------------------------------------------------------------------ //1 //pointed to PBoolean = ^boolean;//bool PByte = ^byte;//byte PShortint = ^shortint;//sbyte //2 PChar = ^char;//char PSmallint = ^smallint;//short PWord = ^word;//ushort //4 PPointer = ^pointer;//void* PInteger = ^integer;//int32 PLongword = ^longword;//uint32 PLongint = ^longint;//int64 //8 PInt64 = ^int64; PUInt64 = ^uint64;//unit64 //8 PSingle = ^single;//single //16 PReal = ^real;//double PDouble = ^double;//double //ошибка, не сохранится, надо исправить //------------------------------------------------------------------------------ // ----------------------------------------------------- // IOSystem interface & IOStandardSystem implementation // ----------------------------------------------------- // размер буфера. Определен эмпирически const buflen = 256; type /// Интерфейс подсистемы ввода/вывода IOSystem = interface function peek: integer; function read_symbol: char; procedure read(var x: integer); procedure read(var x: real); procedure read(var x: char); procedure read(var x: string); procedure read(var x: byte); procedure read(var x: shortint); procedure read(var x: smallint); procedure read(var x: word); procedure read(var x: longword); procedure read(var x: int64); procedure read(var x: uint64); procedure read(var x: single); procedure read(var x: boolean); procedure read(var x: BigInteger); procedure readln; function ReadLine: string; function ReadLexem: string; procedure write(obj: object); procedure write(p: pointer); procedure writeln; end; /// Стандартная подсистема ввода-вывода IOStandardSystem = class(IOSystem) //state := 0; // 0 - нет символа в буфере char, 1 - есть символ в буфере char //sym: integer; // буфер в 1 символ для моделирования Peek в консоли // SSM 28/02/24 - новая концепция для считывания из консоли без редиректа: буфер на одну строку read_buf := new char[0]; rblen := 0; rbpos := 0; buf: array of char := new char[buflen]; pos := 0; realbuflen := -1; // только вначале tr: TextReader; public constructor Create; procedure ReadNextBuf; procedure ReadNextConsoleBuf; function peek: integer; virtual;// использует state и sym (стар) или буфер buf (нов) function read_symbol: char; virtual;// использует state и sym (стар) или буфер buf (нов) procedure read(var x: integer); virtual; procedure read(var x: real); virtual; procedure read(var x: char); virtual; procedure read(var x: string); virtual; procedure read(var x: byte); virtual; procedure read(var x: shortint); virtual; procedure read(var x: smallint); virtual; procedure read(var x: word); virtual; procedure read(var x: longword); virtual; procedure read(var x: int64); virtual; procedure read(var x: uint64); virtual; procedure read(var x: single); virtual; procedure read(var x: boolean); virtual; procedure read(var x: BigInteger); virtual; procedure readln; virtual; function ReadLine: string; virtual; function ReadLexem: string; virtual; procedure write(p: pointer); virtual; procedure write(obj: object); virtual; procedure writeln; virtual; end; // ----------------------------------------------------- // Classes for files & typed sets // ----------------------------------------------------- type /// Тип текстового файла Text = class private fi: FileInfo; sr: StreamReader; sw: TextWriter; public /// Возвращает значение типа integer, введенное из текстового файла function ReadInteger: integer; /// Возвращает значение типа real, введенное из текстового файла function ReadReal: real; /// Возвращает значение типа char, введенное из текстового файла function ReadChar: char; /// Возвращает значение типа string, введенное из текстового файла, без перехода на следующую строку function ReadString: string; /// Возвращает значение типа boolean, введенное из текстового файла function ReadBoolean: boolean; /// Возвращает слово, введенное из текстового файла function ReadWord: string; /// Возвращает значение типа integer, введенное из текстового файла, и переходит на следующую строку function ReadlnInteger: integer; /// Возвращает значение типа real, введенное из текстового файла, и переходит на следующую строку function ReadlnReal: real; /// Возвращает значение типа char, введенное из текстового файла, и переходит на следующую строку function ReadlnChar: char; /// Возвращает значение типа string, введенное из текстового файла, и переходит на следующую строку function ReadlnString: string; /// Возвращает значение типа boolean, введенное из текстового файла, и переходит на следующую строку function ReadlnBoolean: boolean; /// Переходит в файле на следующую строку procedure Readln; /// Записывает в текстовый файл значения procedure Write(params o: array of Object); /// Записывает в текстовый файл значения и переходит на следующую строку procedure Writeln(params o: array of Object); /// Записывает в текстовый файл значения, разделяя их пробелами procedure Print(params o: array of Object); /// Записывает в текстовый файл значения, разделяя их пробелами, и переходит на следующую строку procedure Println(params o: array of Object); /// Возвращает True, если достигнут конец файла, и False в противном случае function Eof: boolean; /// Возвращает True, если достигнут конец строки, и False в противном случае function Eoln: boolean; /// Закрывает файл procedure Close; /// Пропускает пробельные символы, после чего возвращает True, если достигнут конец файла function SeekEof: boolean; /// Пропускает пробельные символы, после чего возвращает True, если достигнут конец строки в файле function SeekEoln: boolean; /// Записывает содержимое буфера файла на диск procedure Flush; /// Удаляет файл procedure Erase; /// Переименовывает файл, давая ему имя newname procedure Rename(newname: string); /// Возвращает имя файла function Name: string; /// Возвращает полное имя файла function FullName: string; /// Возвращает в виде строки содержимое файла от текущего положения до конца function ReadToEnd: string; /// Открывает текстовый файл на чтение в кодировке Windows procedure Reset; /// Открывает текстовый файл на чтение в указанной кодировке procedure Reset(en: Encoding); /// Открывает текстовый файл на запись в кодировке Windows procedure Rewrite; /// Открывает текстовый файл на запись в указанной кодировке procedure Rewrite(en: Encoding); /// Открывает текстовый файл на дополнение в кодировке Windows procedure Append; /// Открывает текстовый файл на дополнение в указанной кодировке procedure Append(en: Encoding); /// Возвращает последовательность строк открытого текстового файла function Lines: sequence of string; end; /// Тип текстового файла TextFile = Text; type // Вспомогательный тип для диапазонного типа ///-- Diapason = record low, high: integer; clow, chigh: object; constructor(_low, _high: integer); constructor(_low, _high: object); end; ///-- {TypedSetComparer = class(System.Collections.IEqualityComparer) public function Equals(x: System.Object; y: System.Object): boolean; public function GetHashCode(obj: System.Object): integer; end;} type EmptyCollection = class; /// Тип встроенного множества NewSet = record(IEnumerable) private public ///-- _hs := new HashSet; ///-- function hs: HashSet; begin if _hs = nil then _hs := new HashSet; Result := _hs; end; constructor (params a: array of T); begin hs.UnionWith(a); end; function GetEnumerator: IEnumerator := hs.GetEnumerator; function System.Collections.IEnumerable.GetEnumerator: System.Collections.IEnumerator := GetEnumerator; /// Преобразовать к строковому представлению function ToString: string; override; /// Количество элементов в множестве function Count: integer := hs.Count; /// Создать копию множества function Clone: NewSet; begin Result.hs.UnionWith(hs) end; /// Добавить элемент в множество function Add(elem: T): boolean := hs.Add(elem); /// Добавить набор элементов в множество. Вернуть True если элемент был добавлен procedure AddRange(elems: sequence of T) := hs.UnionWith(elems); /// Удалить элемент из множества. Вернуть True если элемент был удален function Remove(elem: T): boolean := hs.Remove(elem); static procedure operator +=(Self: NewSet; elem: T) := Self.hs.Add(elem); static procedure operator -=(Self: NewSet; elem: T) := Self.hs.Remove(elem); /// Содержится ли элемент во множестве function Contains(elem: T): boolean := hs.Contains(elem); static function operator in(elem: T; Self: NewSet): boolean; begin Result := Self.hs.Contains(elem); end; static procedure operator+=(Self, another: NewSet) := Self.hs.UnionWith(another.hs); static procedure operator-=(Self, another: NewSet) := Self.hs.ExceptWith(another.hs); static procedure operator*=(Self, another: NewSet) := Self.hs.IntersectWith(another.hs); static function operator+(first, second: NewSet): NewSet; begin Result.hs.UnionWith(first); Result._hs.UnionWith(second); end; static function operator*(first, second: NewSet): NewSet; begin Result.hs.UnionWith(first); Result._hs.IntersectWith(second); end; static function operator-(first, second: NewSet): NewSet; begin Result.hs.UnionWith(first); Result._hs.ExceptWith(second); end; static function operator=(first, second: NewSet) := first.hs.SetEquals(second.hs); {static function operator=(first: NewSet; second: array of T) := first.hs.SetEquals(second); static function operator=(first: array of T; second: NewSet) := second = first;} static function operator<>(first, second: NewSet) := not (first = second); static function operator<(first, second: NewSet) := first.hs.IsProperSubsetOf(second.hs); static function operator<=(first, second: NewSet) := first.hs.IsSubsetOf(second.hs); static function operator>(first, second: NewSet) := first.hs.IsProperSupersetOf(second.hs); static function operator>=(first, second: NewSet) := first.hs.IsSupersetOf(second.hs); static function operator implicit(ns: NewSet): HashSet := ns.ToHashSet; static function operator implicit(ns: HashSet): NewSet; begin Result.hs.UnionWith(ns); end; static function operator implicit(a: array of T): NewSet; begin Result._hs := new HashSet(a); end; static function operator:=(var s: NewSet; st: NewSet): NewSet; // Эту функцию обязательно здесь определять begin s._hs := new HashSet(st.hs); end; static function operator implicit(ns: EmptyCollection): NewSet; begin end; end; EmptyCollection = class public static function operator=(s1: NewSet; s2: EmptyCollection): boolean := s1.Count = 0; static function operator=(s2: EmptyCollection; s1: NewSet): boolean := s1.Count = 0; static function operator<>(s1: NewSet; s2: EmptyCollection): boolean := not (s1 = s2); static function operator<>(s2: EmptyCollection; s1: NewSet): boolean := not (s1 = s2); static function operator>(s1: NewSet; s2: EmptyCollection): boolean := s1.Count > 0; static function operator>(s2: EmptyCollection; s1: NewSet): boolean := False; static function operator<(s1: NewSet; s2: EmptyCollection): boolean := False; static function operator<(s2: EmptyCollection; s1: NewSet): boolean := s1.Count > 0; static function operator>=(s1: NewSet; s2: EmptyCollection): boolean := s1.Count >= 0; static function operator>=(s2: EmptyCollection; s1: NewSet): boolean := False; static function operator<=(s1: NewSet; s2: EmptyCollection): boolean := False; static function operator<=(s2: EmptyCollection; s1: NewSet): boolean := s1.Count >= 0; // ToDo: определить то же для массивов на будущее static function operator+(first, second: EmptyCollection): EmptyCollection := new EmptyCollection; static function operator-(first, second: EmptyCollection): EmptyCollection := new EmptyCollection; static function operator*(first, second: EmptyCollection): EmptyCollection := new EmptyCollection; static function operator+(first: EmptyCollection; second: array of T): NewSet; begin Result.hs.UnionWith(second); end; static function operator+(first: array of T; second: EmptyCollection): NewSet; begin Result.hs.UnionWith(first); end; static function operator+(first: NewSet; second: EmptyCollection): NewSet := first; static function operator+(first: EmptyCollection; second: NewSet): NewSet := second; static function operator*(first: NewSet; second: EmptyCollection): NewSet; begin end; static function operator*(first: EmptyCollection; second: NewSet): NewSet; begin end; static function operator-(first: NewSet; second: EmptyCollection): NewSet := first; static function operator-(first: EmptyCollection; second: NewSet): NewSet; begin end; static function operator*(first: EmptyCollection; second: array of T): NewSet; begin end; static function operator*(first: array of T; second: EmptyCollection): NewSet; begin end; static function operator-(first: EmptyCollection; second: array of T): NewSet; begin end; static function operator-(first: array of T; second: EmptyCollection): NewSet; begin Result.hs.UnionWith(first); end; function ToString: string; override := '{}'; function ToSet(): NewSet; begin end; static function operator implicit(Self: EmptyCollection): array of T; begin Result := System.Array.Empty&; end; static function operator implicit(Self: EmptyCollection): sequence of T; begin Result := System.Array.Empty&; end; static function operator implicit(Self: EmptyCollection): HashSet := new HashSet; static function operator implicit(Self: EmptyCollection): SortedSet := new SortedSet; static function operator implicit(Self: EmptyCollection): List := new List; static function operator implicit(Self: EmptyCollection): Dictionary := new Dictionary; static function operator implicit(Self: EmptyCollection): Stack := new Stack; static function operator implicit(Self: EmptyCollection): Queue := new Queue; end; type // Вспомогательный тип для множества ///-- TypedSet = class (System.Collections.IEnumerable) private ht: Hashtable; len: integer; //copy_ht: Hashtable; low_bound, upper_bound: object; public constructor Create; constructor Create(len: integer); constructor Create(low_bound, upper_bound: object); constructor Create(vals: array of byte); constructor Create(initValue: TypedSet); constructor Create(low_bound, upper_bound: object; initValue: TypedSet); procedure CreateIfNeed; function UnionSet(s: TypedSet): TypedSet; function SubtractSet(s: TypedSet): TypedSet; function IntersectSet(s: TypedSet): TypedSet; function CloneSet: TypedSet; function GetBytes: array of byte; function IsInDiapason(elem: object): boolean; function Contains(elem: object): boolean; procedure Clip; procedure Clip(len: integer); procedure IncludeElement(elem: object); procedure ExcludeElement(elem: object); procedure Init(params elems: array of object); procedure AssignSetFrom(s: TypedSet); function CompareEquals(s: TypedSet): boolean; function CompareInEquals(s: TypedSet): boolean; function CompareLess(s: TypedSet): boolean; function CompareLessEqual(s: TypedSet): boolean; function CompareGreater(s: TypedSet): boolean; function CompareGreaterEqual(s: TypedSet): boolean; function GetEnumerator: System.Collections.IEnumerator; function ToString: string; override; class function operator implicit(s: TypedSet): HashSet; class function operator implicit(s: HashSet): TypedSet; class function InitBy(s: sequence of T): TypedSet; function Count: integer := ht.Count; procedure Print(delim: string := ' '); procedure Println(delim: string := ' '); end; /// Значение пустого множества function EmptySet: EmptyCollection; /// Генератор множества function __NewSetCreatorInternal(params a: array of T): NewSet; /// Генератор множества function __NSetInteger(a: array of integer; dd: array of integer): NewSet; /// Генератор множества function __NSetChar(a: array of char; dd: array of char): NewSet; /// Генератор множества function __NSetEnum(a: array of T; dd: array of T): NewSet; /// Генератор множества function __NSetBoolean(a: array of boolean; dd: array of boolean): NewSet; type // Base class for typed and binary files ///-- AbstractBinaryFile = class private fi: FileInfo; fs: FileStream; br: BinaryReader; bw: BinaryWriter; public /// Закрывает файл procedure Close; /// Усекает двоичный файл, отбрасывая все элементы с позиции файлового указателя procedure Truncate; /// Возвращает True, если достигнут конец файла function Eof: boolean; /// Удаляет файл procedure Erase; /// Переименовывает файл, давая ему имя newname procedure Rename(newname: string); ///- f.Write(a,b,...) /// Выводит значения a,b,... в двоичный файл procedure Write(params vals: array of object); /// Открывает существующий двоичный файл на чтение и запись. Устанавливает файловый указатель на начало файла procedure Reset; /// Открывает двоичный файл на чтение и запись. Если файл не существовал, он создаётся, если существовал, он обнуляется procedure Rewrite; /// Возвращает имя файла function Name: string; /// Возвращает полное имя файла function FullName: string; end; // Class for typed files ///-- TypedFile = sealed class(AbstractBinaryFile) private ElementSize: int64; offset: integer; offsets: array of integer; function GetFilePos: int64; public ElementType: System.Type; constructor Create(ElementType: System.Type); constructor Create(ElementType: System.Type; offs: integer; params offsets: array of integer); function ToString: string; override; /// Возвращает количество элементов в типизированном файле function Size: int64; /// Устанавливает текущую позицию файлового указателя в типизированном файле на элемент с номером n procedure Seek(n: int64); /// Возвращает или устанавливает текущую позицию файлового указателя в типизированном файле property Position: int64 read GetFilePos write Seek; end; // Class for binary files ///-- BinaryFile = sealed class(AbstractBinaryFile) private function GetFilePos: int64; procedure InternalCheck; public function ToString: string; override; /// Открывает существующий бестиповой файл на чтение и запись в указанной кодировке procedure Reset(en: Encoding); /// Открывает существующий бестиповой файл на чтение и запись в указанной кодировке. Если файл не существовал, он создаётся, если существовал, он обнуляется procedure Rewrite(en: Encoding); /// Возвращает количество байт в бестиповом файле function Size: int64; /// Устанавливает текущую позицию файлового указателя в бестиповом файле на байт с номером n procedure Seek(n: int64); /// Возвращает или устанавливает текущую позицию файлового указателя в бестиповом файле property Position: int64 read GetFilePos write Seek; /// Записывает данные из байтового массива в бестиповой файл procedure WriteBytes(a: array of byte); /// Считывает указанное количество байтов из бестипового файла в байтовый массив function ReadBytes(count: integer): array of byte; /// Считывает целое из бестипового файла function ReadInteger: integer; /// Считывает логическое из бестипового файла function ReadBoolean: boolean; /// Считывает байт из бестипового файла function ReadByte: byte; /// Считывает символ из бестипового файла function ReadChar: char; /// Считывает вещественное из бестипового файла function ReadReal: real; /// Считывает строку из бестипового файла function ReadString: string; /// Сериализует объект в файл (объект должен иметь атрибут [Serializable]) procedure Serialize(obj: object); /// Десериализует объект из файла function Deserialize: object; end; type //TODO #2983 /// Тип диапазона целых IntRange = record(ICollection{, IReadOnlyCollection}, IEquatable) private l,h: integer; public constructor(l,h: integer); begin Self.l := l; Self.h := h; end; property Low: integer read l; property High: integer read h; property Count: integer read System.Math.Max(0,h-l+1); property ICollection.IsReadOnly: boolean read boolean(true); procedure ICollection.Add(item: integer) := raise new System.InvalidOperationException; function ICollection.Remove(item: integer): boolean; begin Result := false; raise new System.InvalidOperationException; end; procedure ICollection.Clear := raise new System.InvalidOperationException; static function operator in(x: integer; r: IntRange): boolean := (x >= r.l) and (x <= r.h); static function operator in(x: real; r: IntRange): boolean := (x >= r.l) and (x <= r.h); public function Contains(x: integer) := x in self; public function Contains(x: real) := x in self; static function operator=(r1,r2: IntRange) := (r1.l = r2.l) and (r1.h = r2.h); static function operator<>(r1,r2: IntRange) := not(r1=r2); function Equals(other: IntRange) := self=other; function Equals(o: object): boolean; override; begin Result := false; if not(o is IntRange) then exit; if self <> IntRange(o) then exit; Result := true; end; /// Возвращает True если диапазон пуст function IsEmpty: boolean := l>h; function Step(n: integer): sequence of integer; function Reverse: sequence of integer; function GetEnumerator: IEnumerator; function System.Collections.IEnumerable.GetEnumerator: System.Collections.IEnumerator := Self.GetEnumerator; function ToString: string; override := $'{l}..{h}'; function GetHashCode: integer; override := l.GetHashCode*668265263 xor h.GetHashCode; function ToArray: array of integer; begin Result := new integer[Count]; for var i := 0 to Result.Length - 1 do Result[i] := l+i; end; // .ToList, .ToLinkedList, .ToHashSet, .ToSortedSet: // Эти же методы последовательностей уже проверяют "is ICollection" и затем используют свойство .Count // Только .ToArray перевыделяет память 1 лишний раз: // https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,783a052330e7d48d,references public procedure CopyTo(a: array of integer; arrayIndex: integer) := for var i := 0 to System.Math.Min(self.Count, a.Length-arrayIndex)-1 do a[i+arrayIndex] := l+i; end; //TODO #2983 /// Тип диапазона символов CharRange = record(ICollection{, IReadOnlyCollection}, IEquatable) private l,h: char; public constructor(l,h: char); begin Self.l := l; Self.h := h; end; property Low: char read l; property High: char read h; property Count: integer read System.Math.Max(0, integer(h)-integer(l)+1); property ICollection.IsReadOnly: boolean read boolean(true); procedure ICollection.Add(item: char) := raise new System.InvalidOperationException; function ICollection.Remove(item: char): boolean; begin Result := false; raise new System.InvalidOperationException; end; procedure ICollection.Clear := raise new System.InvalidOperationException; static function operator in(x: char; r: CharRange): boolean := (x >= r.l) and (x <= r.h); public function Contains(x: char) := x in self; static function operator=(r1,r2: CharRange) := (r1.l = r2.l) and (r1.h = r2.h); static function operator<>(r1,r2: CharRange) := not(r1=r2); function Equals(other: CharRange) := self=other; function Equals(o: object): boolean; override; begin Result := false; if not(o is CharRange) then exit; if self <> CharRange(o) then exit; Result := true; end; /// Возвращает True если диапазон пуст function IsEmpty: boolean := l>h; function Step(n: integer): sequence of char; function Reverse: sequence of char; function GetEnumerator: IEnumerator; function System.Collections.IEnumerable.GetEnumerator: System.Collections.IEnumerator := GetEnumerator; function ToString: string; override := $'''{l}''..''{h}'''; function GetHashCode: integer; override := l.GetHashCode*668265263 xor h.GetHashCode; function ToArray: array of char; begin Result := new char[Count]; for var i := 0 to Result.Length - 1 do Result[i] := char(integer(l)+i); end; public procedure CopyTo(a: array of char; arrayIndex: integer) := for var i := 0 to System.Math.Min(self.Count, a.Length-arrayIndex)-1 do a[i+arrayIndex] := char(integer(l)+i); end; /// Тип диапазона вещественных RealRange = record(IEquatable) private l,h: real; public constructor(l,h: real); begin Self.l := l; Self.h := h; end; property Low: real read l; property High: real read h; property Size: real read System.Math.Max(0, h-l); static function operator in(x: real; r: RealRange): boolean := (x >= r.l) and (x <= r.h); static function operator=(r1,r2: RealRange) := (r1.l = r2.l) and (r1.h = r2.h); static function operator<>(r1,r2: RealRange) := not(r1=r2); function Equals(other: RealRange) := self=other; function Equals(o: object): boolean; override; begin Result := false; if not(o is RealRange) then exit; if self <> RealRange(o) then exit; Result := true; end; /// Возвращает True если диапазон пуст function IsEmpty: boolean := l>h; function ToString: string; override := $'{l}..{h}'; function GetHashCode: integer; override := l.GetHashCode*668265263 xor h.GetHashCode; end; ///Тип для представления индекса SystemIndex = record private val: integer; inverted: boolean; public property IndexValue: integer read val write val; property IsInverted: boolean read inverted; constructor(val: integer; inverted: boolean); begin Self.val := val; Self.inverted := inverted; end; static function operator implicit(i: integer): SystemIndex := new SystemIndex(i, false); function Reverse(list: List): integer := list.Count - IndexValue; function Reverse(arr: array of T): integer := arr.Length - IndexValue; function Reverse0(str: string) := str.Length - IndexValue; function Reverse(str: string) := str.Length - IndexValue + 1; function Reverse(arr: System.Array; dim: integer): integer := arr.GetLength(dim) - IndexValue; end; //{{{doc: Начало секции интерфейса для документации }}} // ----------------------------------------------------- //>> Подпрограммы ввода # Read subroutines // ----------------------------------------------------- ///- procedure Read(a,b,...); /// Вводит значения a,b,... с клавиатуры procedure Read; ///-- procedure Read(var x: integer); ///-- procedure Read(var x: real); ///-- procedure Read(var x: char); ///-- procedure Read(var x: string); ///-- procedure Read(var x: byte); ///-- procedure Read(var x: shortint); ///-- procedure Read(var x: smallint); ///-- procedure Read(var x: word); ///-- procedure Read(var x: longword); ///-- procedure Read(var x: int64); ///-- procedure Read(var x: uint64); ///-- procedure Read(var x: single); ///-- procedure Read(var x: boolean); ///-- procedure Read(var x: BigInteger); ///- procedure Readln(a,b,...); /// Вводит значения a,b,... с клавиатуры и осуществляет переход на следующую строку procedure Readln; ///- function TryRead(var x: число): boolean; /// Вводит числовое значение x с клавиатуры. Возвращает False если при вводе произошла ошибка function TryRead(var x: integer; message: string := ''): boolean; ///- function TryRead(var x: число; message: string): boolean; /// Выводит приглашение к вводу и вводит числовое значение x с клавиатуры. Возвращает False если при вводе произошла ошибка function TryRead(var x: real; message: string := ''): boolean; ///-- function TryRead(var x: byte; message: string := ''): boolean; ///-- function TryRead(var x: shortint; message: string := ''): boolean; ///-- function TryRead(var x: smallint; message: string := ''): boolean; ///-- function TryRead(var x: word; message: string := ''): boolean; ///-- function TryRead(var x: longword; message: string := ''): boolean; ///-- function TryRead(var x: int64; message: string := ''): boolean; ///-- function TryRead(var x: uint64; message: string := ''): boolean; ///-- function TryRead(var x: single; message: string := ''): boolean; ///-- function TryRead(var x: BigInteger; message: string := ''): boolean; /// Вводит логическое значение x с клавиатуры. Возвращает False если при вводе произошла ошибка function TryRead(var x: boolean; message: string := ''): boolean; /// Возвращает значение типа integer, введенное с клавиатуры function ReadInteger: integer; /// Возвращает значение типа int64, введенное с клавиатуры function ReadInt64: int64; /// Возвращает значение типа real, введенное с клавиатуры function ReadReal: real; /// Возвращает значение типа char, введенное с клавиатуры function ReadChar: char; /// Возвращает значение типа string, введенное с клавиатуры function ReadString: string; /// Возвращает значение типа boolean, введенное с клавиатуры function ReadBoolean: boolean; /// Возвращает значение типа BigInteger, введенное с клавиатуры function ReadBigInteger: BigInteger; /// Возвращает следующую лексему function ReadLexem: string; /// Возвращает значение типа integer, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger: integer; /// Возвращает значение типа int64, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnInt64: int64; /// Возвращает значение типа real, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnReal: real; /// Возвращает значение типа char, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnChar: char; /// Возвращает значение типа string, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnString: string; /// Возвращает значение типа boolean, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnBoolean: boolean; /// Возвращает значение типа BigInteger, введенное с клавиатуры, и переходит на следующую строку ввода function ReadlnBigInteger: BigInteger; /// Возвращает кортеж из двух значений типа integer, введенных с клавиатуры function ReadInteger2: (integer, integer); /// Возвращает кортеж из двух значений типа real, введенных с клавиатуры function ReadReal2: (real, real); /// Возвращает кортеж из двух значений типа char, введенных с клавиатуры function ReadChar2: (char, char); /// Возвращает кортеж из двух значений типа string, введенных с клавиатуры function ReadString2: (string, string); /// Возвращает кортеж из двух значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger2: (integer, integer); /// Возвращает кортеж из двух значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal2: (real, real); /// Возвращает кортеж из двух значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar2: (char, char); /// Возвращает кортеж из двух значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString2: (string, string); /// Возвращает кортеж из трёх значений типа integer, введенных с клавиатуры function ReadInteger3: (integer, integer, integer); /// Возвращает кортеж из трёх значений типа real, введенных с клавиатуры function ReadReal3: (real, real, real); /// Возвращает кортеж из трёх значений типа char, введенных с клавиатуры function ReadChar3: (char, char, char); /// Возвращает кортеж из трёх значений типа string, введенных с клавиатуры function ReadString3: (string, string, string); /// Возвращает кортеж из трёх значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger3: (integer, integer, integer); /// Возвращает кортеж из трёх значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal3: (real, real, real); /// Возвращает кортеж из трёх значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar3: (char, char, char); /// Возвращает кортеж из трёх значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString3: (string, string, string); /// Возвращает кортеж из четырёх значений типа integer, введенных с клавиатуры function ReadInteger4: (integer, integer, integer, integer); /// Возвращает кортеж из четырёх значений типа real, введенных с клавиатуры function ReadReal4: (real, real, real, real); /// Возвращает кортеж из четырёх значений типа char, введенных с клавиатуры function ReadChar4: (char, char, char, char); /// Возвращает кортеж из четырёх значений типа string, введенных с клавиатуры function ReadString4: (string, string, string, string); /// Возвращает кортеж из четырёх значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger4: (integer, integer, integer, integer); /// Возвращает кортеж из четырёх значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal4: (real, real, real, real); /// Возвращает кортеж из четырёх значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar4: (char, char, char, char); /// Возвращает кортеж из четырёх значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString4: (string, string, string, string); /// Возвращает кортеж из двух значений типа integer, введенных с клавиатуры function ReadInteger2(prompt: string): (integer, integer); /// Возвращает кортеж из двух значений типа real, введенных с клавиатуры function ReadReal2(prompt: string): (real, real); /// Возвращает кортеж из двух значений типа char, введенных с клавиатуры function ReadChar2(prompt: string): (char, char); /// Возвращает кортеж из двух значений типа string, введенных с клавиатуры function ReadString2(prompt: string): (string, string); /// Возвращает кортеж из двух значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger2(prompt: string): (integer, integer); /// Возвращает кортеж из двух значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal2(prompt: string): (real, real); /// Возвращает кортеж из двух значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar2(prompt: string): (char, char); /// Возвращает кортеж из двух значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString2(prompt: string): (string, string); /// Возвращает кортеж из трёх значений типа integer, введенных с клавиатуры function ReadInteger3(prompt: string): (integer, integer, integer); /// Возвращает кортеж из трёх значений типа real, введенных с клавиатуры function ReadReal3(prompt: string): (real, real, real); /// Возвращает кортеж из трёх значений типа char, введенных с клавиатуры function ReadChar3(prompt: string): (char, char, char); /// Возвращает кортеж из трёх значений типа string, введенных с клавиатуры function ReadString3(prompt: string): (string, string, string); /// Возвращает кортеж из трёх значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger3(prompt: string): (integer, integer, integer); /// Возвращает кортеж из трёх значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal3(prompt: string): (real, real, real); /// Возвращает кортеж из трёх значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar3(prompt: string): (char, char, char); /// Возвращает кортеж из трёх значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString3(prompt: string): (string, string, string); /// Возвращает кортеж из четырёх значений типа integer, введенных с клавиатуры function ReadInteger4(prompt: string): (integer, integer, integer, integer); /// Возвращает кортеж из четырёх значений типа real, введенных с клавиатуры function ReadReal4(prompt: string): (real, real, real, real); /// Возвращает кортеж из четырёх значений типа char, введенных с клавиатуры function ReadChar4(prompt: string): (char, char, char, char); /// Возвращает кортеж из четырёх значений типа string, введенных с клавиатуры function ReadString4(prompt: string): (string, string, string, string); /// Возвращает кортеж из четырёх значений типа integer, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnInteger4(prompt: string): (integer, integer, integer, integer); /// Возвращает кортеж из четырёх значений типа real, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnReal4(prompt: string): (real, real, real, real); /// Возвращает кортеж из четырёх значений типа char, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnChar4(prompt: string): (char, char, char, char); /// Возвращает кортеж из четырёх значений типа string, введенных с клавиатуры, и переходит на следующую строку ввода function ReadlnString4(prompt: string): (string, string, string, string); /// Выводит приглашение к вводу и возвращает значение типа integer, введенное с клавиатуры function ReadInteger(prompt: string): integer; /// Выводит приглашение к вводу и возвращает значение типа int64, введенное с клавиатуры function ReadInt64(prompt: string): int64; /// Выводит приглашение к вводу и возвращает значение типа real, введенное с клавиатуры function ReadReal(prompt: string): real; /// Выводит приглашение к вводу и возвращает значение типа char, введенное с клавиатуры function ReadChar(prompt: string): char; /// Выводит приглашение к вводу и возвращает значение типа string, введенное с клавиатуры function ReadString(prompt: string): string; /// Выводит приглашение к вводу и возвращает значение типа boolean, введенное с клавиатуры function ReadBoolean(prompt: string): boolean; /// Выводит приглашение к вводу и возвращает значение типа BigInteger, введенное с клавиатуры function ReadBigInteger(prompt: string): BigInteger; /// Выводит приглашение к вводу и возвращает значение типа integer, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnInteger(prompt: string): integer; /// Выводит приглашение к вводу и возвращает значение типа int64, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnInt64(prompt: string): int64; /// Выводит приглашение к вводу и возвращает значение типа real, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnReal(prompt: string): real; /// Выводит приглашение к вводу и возвращает значение типа char, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnChar(prompt: string): char; /// Выводит приглашение к вводу и возвращает значение типа string, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnString(prompt: string): string; /// Выводит приглашение к вводу и возвращает значение типа boolean, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnBoolean(prompt: string): boolean; /// Выводит приглашение к вводу и возвращает значение типа BigInteger, введенное с клавиатуры, ///и осуществляет переход на следующую строку ввода function ReadlnBigInteger(prompt: string): BigInteger; ///-- procedure ReadShortString(var s: string; n: integer); ///-- procedure ReadShortStringFromFile(f: Text; var s: string; n: integer); ///- procedure Read(f: файл; a,b,...); /// Вводит значения a,b,... из файла f procedure Read(f: Text); ///-- procedure Read(f: Text; var x: integer); ///-- procedure Read(f: Text; var x: real); ///-- procedure Read(f: Text; var x: char); ///-- procedure Read(f: Text; var x: string); ///-- procedure Read(f: Text; var x: byte); ///-- procedure Read(f: Text; var x: shortint); ///-- procedure Read(f: Text; var x: smallint); ///-- procedure Read(f: Text; var x: word); ///-- procedure Read(f: Text; var x: longword); ///-- procedure Read(f: Text; var x: int64); ///-- procedure Read(f: Text; var x: uint64); ///-- procedure Read(f: Text; var x: single); ///-- procedure Read(f: Text; var x: boolean); ///- procedure Readln(f: Text; a,b,...); /// Вводит значения a,b,... из текстового файла f и осуществляет переход на следующую строку procedure Readln(f: Text); ///-- procedure Readln(f: Text; var x: string); /// Возвращает значение типа integer, введенное из текстового файла f function ReadInteger(f: Text): integer; /// Возвращает значение типа int64, введенное из текстового файла f function ReadInt64(f: Text): int64; /// Возвращает значение типа real, введенное из текстового файла f function ReadReal(f: Text): real; /// Возвращает значение типа char, введенное из текстового файла f function ReadChar(f: Text): char; /// Возвращает значение типа string, введенное из текстового файла f function ReadString(f: Text): string; /// Возвращает значение типа boolean, введенное из текстового файла f function ReadBoolean(f: Text): boolean; /// Возвращает следующую лексему из текстового файла f function ReadLexem(f: Text): string; /// Возвращает значение типа integer, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnInteger(f: Text): integer; /// Возвращает значение типа int64, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnInt64(f: Text): int64; /// Возвращает значение типа real, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnReal(f: Text): real; /// Возвращает значение типа char, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnChar(f: Text): char; /// Возвращает значение типа string, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnString(f: Text): string; /// Возвращает значение типа boolean, введенное из текстового файла f, ///и осуществляет переход на следующую строку function ReadlnBoolean(f: Text): boolean; // ----------------------------------------------------- //>> Подпрограммы вывода # Write subroutines // ----------------------------------------------------- ///- procedure Write(a,b,...); /// Выводит значения a,b,... на экран procedure Write; ///-- procedure Write(obj: object); ///-- procedure Write(obj1, obj2: object); ///-- procedure Write(params args: array of object); ///- procedure Writeln(a,b,...); /// Выводит значения a,b,... на экран и осуществляет переход на новую строку ///!!- Writeln(a,b,...) /// Writes a,b,... to standart output stream and appends newline procedure Writeln; ///-- procedure Writeln(obj: object); ///-- //procedure writeln(ptr: pointer); ///-- procedure Writeln(obj1, obj2: object); ///-- procedure Writeln(params args: array of object); ///- procedure Write(f: файл; a,b,...); /// Выводит значения a,b,... в файл f procedure Write(f: Text); ///-- procedure Write(f: Text; val: object); ///-- procedure Write(f: Text; params args: array of object); ///- procedure Writeln(f: Text; a,b,...); /// Выводит значения a,b,... в текстовый файл f и осуществляет переход на новую строку procedure Writeln(f: Text); ///-- procedure Writeln(f: Text; val: object); ///-- procedure Writeln(f: Text; params args: array of object); /// Выводит значения args согласно форматной строке formatstr procedure WriteFormat(formatstr: string; params args: array of object); /// Выводит значения args согласно форматной строке formatstr и осуществляет переход на новую строку procedure WritelnFormat(formatstr: string; params args: array of object); /// Выводит значения args в текстовый файл f согласно форматной строке formatstr procedure WriteFormat(f: Text; formatstr: string; params args: array of object); /// Выводит значения args в текстовый файл f согласно форматной строке formatstr ///и осуществляет переход на новую строку procedure WritelnFormat(f: Text; formatstr: string; params args: array of object); ///- procedure Print(a,b,...); /// Выводит значения a,b,... на экран, после каждого значения выводит пробел procedure Print(o: object); ///-- procedure Print(s: string); ///-- procedure Print(params args: array of object); ///- procedure Print(f: Text; a,b,...); /// Выводит значения a,b,... в текстовый файл f, после каждого значения выводит пробел procedure Print(f: Text; params args: array of object); ///- procedure Println(a,b,...); /// Выводит значения a,b,... на экран, после каждого значения выводит пробел и переходит на новую строку procedure Println(params args: array of object); ///- procedure Println(f: Text; a,b,...); /// Выводит значения a,b,... в текстовый файл f, после каждого значения выводит пробел и переходит на новую строку procedure Println(f: Text; params args: array of object); /// Сериализует объект в файл (объект должен иметь атрибут [Serializable]) procedure Serialize(fileName: string; obj: object); /// Десериализует объект из файла function Deserialize(fileName: string): object; // ----------------------------------------------------- //>> Общие подпрограммы для работы с файлами # Common subroutines for files // ----------------------------------------------------- ///- procedure Assign(f: файл; fileName: string); /// Связывает файловую переменную с файлом на диске procedure Assign(f: AbstractBinaryFile; fileName: string); ///- procedure AssignFile(f: файл; fileName: string); /// Связывает файловую переменную с файлом на диске procedure AssignFile(f: AbstractBinaryFile; fileName: string); ///- procedure Close(f: файл); /// Закрывает файл procedure Close(f: AbstractBinaryFile); ///- procedure CloseFile(f: файл); /// Закрывает файл procedure CloseFile(f: AbstractBinaryFile); ///- function Eof(f: файл): boolean; /// Возвращает True, если достигнут конец файла function Eof(f: AbstractBinaryFile): boolean; ///- procedure Erase(f: файл); /// Удаляет файл, связанный с файловой переменной procedure Erase(f: AbstractBinaryFile); ///- procedure Rename(f: файл; newname: string); /// Переименовывает файл, связаный с файловой переменной, давая ему имя newname. procedure Rename(f: AbstractBinaryFile; newname: string); // ----------------------------------------------------- //>> Подпрограммы для работы с текстовыми файлами # Subroutines for text files // ----------------------------------------------------- ///-- procedure Assign(f: Text; fileName: string); ///-- procedure AssignFile(f: Text; fileName: string); ///-- procedure Close(f: Text); ///-- procedure CloseFile(f: Text); /// Открывает текстовый файл на чтение в кодировке Windows procedure Reset(f: Text); /// Открывает текстовый файл на чтение в указанной кодировке procedure Reset(f: Text; en: Encoding); /// Связывает файловую переменную f с именем файла fileName и открывает текстовый файл на чтение в кодировке Windows procedure Reset(f: Text; fileName: string); /// Связывает файловую переменную f с именем файла fileName и открывает текстовый файл на чтение в указанной кодировке procedure Reset(f: Text; fileName: string; en: Encoding); /// Открывает текстовый файл на запись в кодировке Windows. ///Если файл существовал - он обнуляется, если нет - создается пустой procedure Rewrite(f: Text); /// Открывает текстовый файл на запись в указанной кодировке. ///Если файл существовал - он обнуляется, если нет - создается пустой procedure Rewrite(f: Text; en: Encoding); /// Связывает файловую переменную с именем файла fileName и открывает текстовый файл f на запись в кодировке Windows. ///Если файл существовал - он обнуляется, если нет - создается пустой procedure Rewrite(f: Text; fileName: string); /// Связывает файловую переменную f с именем файла fileName и открывает текстовый файл f на запись в указанной кодировке. ///Если файл существовал - он обнуляется, если нет - создается пустой procedure Rewrite(f: Text; fileName: string; en: Encoding); /// Открывает текстовый файл на дополнение в кодировке Windows procedure Append(f: Text); /// Открывает текстовый файл на дополнение в указанной кодировке procedure Append(f: Text; en: Encoding); /// Связывает файловую переменную f с именем файла fileName и открывает текстовый файл на дополнение в кодировке Windows procedure Append(f: Text; fileName: string); /// Связывает файловую переменную f с именем файла fileName и открывает текстовый файл на дополнение в указанной кодировке procedure Append(f: Text; fileName: string; en: Encoding); /// Возвращает текстовый файл с именем fileName, открытый на чтение в кодировке Windows function OpenRead(fileName: string): Text; /// Возвращает текстовый файл с именем fileName, открытый на чтение в указанной кодировке function OpenRead(fileName: string; en: Encoding): Text; /// Возвращает текстовый файл с именем fileName, открытый на запись в кодировке Windows function OpenWrite(fileName: string): Text; /// Возвращает текстовый файл с именем fileName, открытый на запись в указанной кодировке function OpenWrite(fileName: string; en: Encoding): Text; /// Возвращает текстовый файл с именем fileName, открытый на дополнение в кодировке Windows function OpenAppend(fileName: string): Text; /// Возвращает текстовый файл с именем fileName, открытый на дополнение в указанной кодировке function OpenAppend(fileName: string; en: Encoding): Text; ///-- function Eof(f: Text): boolean; /// Возвращает True, если в файле достигнут конец строки function Eoln(f: Text): boolean; /// Пропускает пробельные символы, после чего возвращает True, если достигнут конец файла function SeekEof(f: Text): boolean; /// Пропускает пробельные символы, после чего возвращает True, если в файле достигнут конец строки function SeekEoln(f: Text): boolean; /// Записывает содержимое буфера файла на диск procedure Flush(f: Text); ///-- procedure Erase(f: Text); ///-- procedure Rename(f: Text; newname: string); ///-- procedure TextFileInit(var f: Text); /// Открывает файл, считывает из него строки в кодировке Windows и закрывает файл. В каждый момент в памяти хранится только текущая строка function ReadLines(path: string): sequence of string; /// Открывает файл, считывает из него строки в указаной кодировке и закрывает файл. В каждый момент в памяти хранится только текущая строка function ReadLines(path: string; en: Encoding): sequence of string; /// Открывает файл, считывает из него строки в кодировке Windows в виде массива строк, после чего закрывает файл function ReadAllLines(path: string): array of string; /// Открывает файл, считывает из него строки в указаной кодировке в виде массива строк, после чего закрывает файл function ReadAllLines(path: string; en: Encoding): array of string; /// Открывает файл, считывает его содержимое в кодировке Windows в виде строки, после чего закрывает файл function ReadAllText(path: string): string; /// Открывает файл, считывает его содержимое в указаной кодировке в виде строки, после чего закрывает файл function ReadAllText(path: string; en: Encoding): string; /// Создает новый файл, записывает в него строки из последовательности в кодировке Windows, после чего закрывает файл procedure WriteLines(path: string; ss: sequence of string); /// Создает новый файл, записывает в него строки из последовательности в указанной кодировке, после чего закрывает файл procedure WriteLines(path: string; ss: sequence of string; en: Encoding); /// Создает новый файл, записывает в него строки из массива в кодировке Windows, после чего закрывает файл procedure WriteAllLines(path: string; ss: array of string); /// Создает новый файл, записывает в него строки из массива в указанной кодировке, после чего закрывает файл procedure WriteAllLines(path: string; ss: array of string; en: Encoding); /// Создает новый файл, записывает в него строку в кодировке Windows, после чего закрывает файл procedure WriteAllText(path: string; s: string); /// Создает новый файл, записывает в него строку в указанной кодировке, после чего закрывает файл procedure WriteAllText(path: string; s: string; en: Encoding); // ----------------------------------------------------- //>> Подпрограммы для работы с двоичными файлами # Subroutines for binary files // ----------------------------------------------------- ///- procedure Reset(f: двоичный файл); /// Открывает двоичный файл на чтение и запись. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Reset(f: AbstractBinaryFile); ///- procedure Reset(f: двоичный файл; fileName: string); /// Связывает файловую переменную f с файлом name на диске и открывает двоичный файл на чтение и запись. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Reset(f: AbstractBinaryFile; fileName: string); ///- procedure Rewrite(f: двоичный файл); /// Открывает двоичный файл на чтение и запись, при этом обнуляя его содержимое. Если файл существовал, он обнуляется. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Rewrite(f: AbstractBinaryFile); ///- procedure Rewrite(f: двоичный файл; fileName: string); /// Связывает файловую переменную f с файлом fileName на диске и открывает двоичный файл на чтение и запись, при этом обнуляя его содержимое. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Rewrite(f: AbstractBinaryFile; fileName: string); ///- procedure Reset(f: двоичный файл; en: Encoding); /// Открывает двоичный файл на чтение и запись в заданной кодировке. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Reset(f: AbstractBinaryFile; en: Encoding); ///- procedure Reset(f: двоичный файл; fileName: string; en: Encoding); /// Связывает файловую переменную f с файлом fileName на диске и открывает двоичный файл на чтение и запись в заданной кодировке. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Reset(f: AbstractBinaryFile; fileName: string; en: Encoding); ///- procedure Rewrite(f: двоичный файл; en: Encoding); /// Открывает двоичный файл на чтение и запись в заданной кодировке, при этом обнуляя его содержимое. Если файл существовал, он обнуляется. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Rewrite(f: AbstractBinaryFile; en: Encoding); ///- procedure Rewrite(f: двоичный файл; fileName: string; en: Encoding); /// Связывает файловую переменную f с файлом fileName на диске и открывает двоичный файл на чтение и запись в заданной кодировке, при этом обнуляя его содержимое. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Rewrite(f: AbstractBinaryFile; fileName: string; en: Encoding); ///- procedure Truncate(f: двоичный файл); /// Усекает двоичный файл, отбрасывая все элементы с позиции файлового указателя. ///Двоичный файл - это либо типизированный файл file of T, либо бестиповой файл file procedure Truncate(f: AbstractBinaryFile); ///-- procedure Write(f: AbstractBinaryFile; params vals: array of object); ///-- procedure Writeln(f: AbstractBinaryFile); ///-- procedure Writeln(f: AbstractBinaryFile; val: object); ///-- procedure Writeln(f: AbstractBinaryFile; params vals: array of object); ///- function FilePos(f: двоичный файл): int64; /// Возвращает текущую позицию файлового указателя в двоичном файле function FilePos(f: TypedFile): int64; ///- function FileSize(f: двоичный файл): int64; /// Возвращает количество элементов в двоичном файле function FileSize(f: TypedFile): int64; ///- procedure Seek(f: двоичный файл; n: int64); /// Устанавливает текущую позицию файлового указателя в двоичном файле на элемент с данным номером procedure Seek(f: TypedFile; n: int64); ///-- procedure TypedFileInit(var f: TypedFile; ElementType: System.Type); ///-- procedure TypedFileInit(var f: TypedFile; ElementType: System.Type; off: integer; params offs: array of integer); ///-- procedure TypedFileInitWithShortString(var f: TypedFile; ElementType: System.Type; off: integer; params offs: array of integer); ///-- function TypedFileRead(f: TypedFile): object; ///-- function FilePos(f: BinaryFile): int64; ///-- function FileSize(f: BinaryFile): int64; ///-- procedure Seek(f: BinaryFile; n: int64); ///-- procedure BinaryFileInit(var f: BinaryFile); ///-- function BinaryFileRead(var f: BinaryFile; ElementType: System.Type): object; // ----------------------------------------------------- //>> Cистемные подпрограммы # System subroutines // ----------------------------------------------------- /// Возвращает версию PascalABC.NET function PascalABCVersion: string; /// Возвращает количество параметров командной строки function ParamCount: integer; /// Возвращает i-тый параметр командной строки function ParamStr(i: integer): string; /// Возвращает текущий каталог function GetDir: string; /// Меняет текущий каталог procedure ChDir(dirName: string); /// Создает каталог procedure MkDir(dirName: string); /// Удаляет каталог procedure RmDir(dirName: string); /// Создает каталог. Возвращает True, если каталог успешно создан function CreateDir(dirName: string): boolean; /// Удаляет файл. Если файл не может быть удален, то возвращает False function DeleteFile(fileName: string): boolean; /// Возвращает текущий каталог function GetCurrentDir: string; /// Удаляет каталог. Возвращает True, если каталог успешно удален function RemoveDir(dirName: string): boolean; /// Переименовывает файл fileName, давая ему новое имя newfileName. Возвращает True, если файл успешно переименован function RenameFile(fileName, newfileName: string): boolean; /// Переименовывает каталог dirName, давая ему новое имя newDirName. Возвращает True, если каталог успешно переименован function RenameDirectory(dirName, newDirName: string): boolean; /// Устанавливает текущий каталог. Возвращает True, если каталог успешно удален function SetCurrentDir(dirName: string): boolean; /// Изменяет расширение файла с именем fileName на newExt function ChangeFileNameExtension(fileName, newExt: string): string; /// Возвращает True, если файл с именем fileName существует function FileExists(fileName: string): boolean; ///- procedure Assert(cond: boolean); /// Выводит в специальном окне стек вызовов подпрограмм если условие не выполняется procedure Assert(cond: boolean; sourceFile: string := ''; line: integer := 0); ///- procedure Assert(cond: boolean; message: string); /// Выводит в специальном окне диагностическое сообщение и стек вызовов подпрограмм если условие не выполняется procedure Assert(cond: boolean; message: string; sourceFile: string := ''; line: integer := 0); /// Возвращает свободное место в байтах на диске с именем diskname function DiskFree(diskName: string): int64; /// Возвращает размер в байтах на диске с именем diskname function DiskSize(diskName: string): int64; /// Возвращает свободное место в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д. function DiskFree(disk: integer): int64; /// Возвращает размер в байтах на диске disk. disk=0 - текущий диск, disk=1 - диск A: , disk=2 - диск B: и т.д. function DiskSize(disk: integer): int64; /// Возвращает количество миллисекунд с момента начала работы программы function Milliseconds: integer; /// Возвращает количество миллисекунд с момента последнего вызова Milliseconds или MillisecondsDelta или начала программы function MillisecondsDelta: integer; /// Завершает работу программы procedure Halt; /// Завершает работу программы, возвращая код ошибки exitCode procedure Halt(exitCode: integer); /// Делает паузу на ms миллисекунд procedure Sleep(ms: integer); /// Возващает имя запущенного .exe-файла function GetEXEFileName: string; /// Преобразует указатель к строковому представлению function PointerToString(p: pointer): string; /// Запускает программу или документ с именем fileName procedure Exec(fileName: string); /// Запускает программу или документ с именем fileName и параметрами командной строки args procedure Exec(fileName: string; args: string); /// Запускает программу или документ с именем fileName procedure Execute(fileName: string); /// Запускает программу или документ с именем fileName и параметрами командной строки args procedure Execute(fileName: string; args: string); /// Возвращает последовательность имен файлов по заданному пути, соответствующих шаблону поиска function EnumerateFiles(path: string; searchPattern: string := '*.*'): sequence of string; /// Возвращает последовательность имен файлов по заданному пути, соответствующих шаблону поиска, включая подкаталоги function EnumerateAllFiles(path: string; searchPattern: string := '*.*'): sequence of string; /// Возвращает последовательность имен каталогов по заданному пути function EnumerateDirectories(path: string): sequence of string; /// Возвращает последовательность имен каталогов по заданному пути, включая подкаталоги function EnumerateAllDirectories(path: string): sequence of string; /// Возвращает строку с именем данного типа function TypeToTypeName(t: System.Type): string; /// Возвращает строку с именем типа объекта function TypeName(obj: object): string; /// Создаёт настройки форматирования числовых значений function NumberFormat(DecimalSeparator: string := '.'; GroupSeparator: string := ',') : NumberFormatInfo; /// Устанавливает разделитель между целой и дробной частью в вещественных значениях procedure SetDecimalSeparator(sep: string); /// Устанавливает параметры числового формата procedure SetNumberFormat(DecimalSeparator: string := '.'; GroupSeparator: string := ','); ///-procedure New(var p: ^T); /// Выделяет динамическую память размера sizeof(T) и возвращает в переменной p указатель на нее. Тип T должен быть размерным //procedure New(var p: ^T); ///-procedure Dispose(var p: ^T); /// Освобождает динамическую память, на которую указывает p //procedure Dispose(var p: ^T); // ----------------------------------------------------- //>> Подпрограммы для работы с именами файлов # Functions for file names // ----------------------------------------------------- /// Выделяет имя файла из полного имени файла fileName function ExtractFileName(fileName: string): string; /// Выделяет расширение из полного имени файла fileName function ExtractFileExt(fileName: string): string; /// Выделяет путь из полного имени файла fileName function ExtractFilePath(fileName: string): string; /// Выделяет имя диска и путь из полного имени файла fileName function ExtractFileDir(fileName: string): string; /// Выделяет путь из полного имени файла fileName function ExtractFileDrive(fileName: string): string; /// Возвращает полное имя файла fileName function ExpandFileName(fileName: string): string; // ----------------------------------------------------- //>> Математические подпрограммы # Math subroutines // ----------------------------------------------------- ///-function Sign(x: число): integer; /// Возвращает -1, 0 или +1 в зависимости от знака числа x function Sign(x: shortint): integer; ///-- function Sign(x: smallint): integer; ///-- function Sign(x: integer): integer; ///-- function Sign(x: int64): integer; ///-- function Sign(x: byte): integer; ///-- function Sign(x: word): integer; ///-- function Sign(x: longword): integer; ///-- function Sign(x: uint64): integer; ///-- function Sign(x: real): integer; ///-- function Sign(x: BigInteger): integer; ///-function Abs(x: число): число; /// Возвращает модуль числа x function Abs(x: shortint): shortint; ///-- function Abs(x: smallint): smallint; ///-- function Abs(x: integer): integer; ///-- function Abs(x: int64): int64; ///-- function Abs(x: byte): byte; ///-- function Abs(x: word): word; ///-- function Abs(x: longword): longword; ///-- function Abs(x: uint64): uint64; ///-- function Abs(x: BigInteger): BigInteger; ///-- function Abs(x: real): real; ///-- function Abs(x: single): single; /// Возвращает синус угла x, измеряемого в радианах function Sin(x: real): real; /// Возвращает гиперболический синус угла x, измеряемого в радианах function Sinh(x: real): real; /// Возвращает косинус угла x, измеряемого в радианах /// !! Returns the cosine of number x function Cos(x: real): real; /// Возвращает гиперболический косинус угла x, измеряемого в радианах function Cosh(x: real): real; /// Возвращает тангенс угла x, измеряемого в радианах function Tan(x: real): real; /// Возвращает гиперболический тангенс угла x, измеряемого в радианах function Tanh(x: real): real; /// Возвращает угол в радианах, синус которого равен x, -1<=x<=1 function ArcSin(x: real): real; /// Возвращает угол в радианах, косинус которого равен x, -1<=x<=1 function ArcCos(x: real): real; /// Возвращает угол в радианах, тангенс которого равен x function ArcTan(x: real): real; /// Возвращает экспоненту числа x function Exp(x: real): real; /// Возвращает натуральный логарифм числа x function Ln(x: real): real; /// Возвращает натуральный логарифм числа x function Log(x: real): real; /// Возвращает логарифм числа x по основанию 2 function Log2(x: real): real; /// Возвращает десятичный логарифм числа x function Log10(x: real): real; /// Возвращает логарифм числа x по основанию base function LogN(base, x: real): real; /// Возвращает квадратный корень числа x function Sqrt(x: real): real; ///-function Sqr(x: число): число; /// Возвращает квадрат числа x function Sqr(x: shortint): integer; ///-- function Sqr(x: smallint): integer; ///-- function Sqr(x: integer): int64; ///-- function Sqr(x: int64): int64; ///-- function Sqr(x: byte): integer; ///-- function Sqr(x: word): uint64; ///-- function Sqr(x: longword): uint64; ///-- function Sqr(x: uint64): uint64; ///-- function Sqr(x: BigInteger): BigInteger; ///-- function Sqr(x: real): real; /// Возвращает x в степени y function Power(x, y: real): real; /// Возвращает x в целой степени n function Power(x: real; n: integer): real; /// Возвращает x в степени y function Power(x: BigInteger; y: integer): BigInteger; /// Возвращает x, округленное до ближайшего целого. Если вещественное находится посередине между двумя целыми, ///то округление осуществляется к ближайшему четному (банковское округление): Round(2.5)=2, Round(3.5)=4 function Round(x: real): integer; /// Возвращает x, округленное до ближайшего вещественного с digits знаками после десятичной точки function Round(x: real; digits: integer): real; /// Возвращает x, округленное до ближайшего длинного целого function RoundBigInteger(x: real): BigInteger; /// Возвращает целую часть вещественного числа x function Trunc(x: real): integer; /// Возвращает целую часть вещественного числа x как длинное целое function TruncBigInteger(x: real): BigInteger; /// Возвращает целую часть числа x function Int(x: real): real; /// Возвращает дробную часть числа x function Frac(x: real): real; /// Возвращает наибольшее целое <= x function Floor(x: real): integer; /// Возвращает наименьшее целое >= x function Ceil(x: real): integer; /// Переводит радианы в градусы function RadToDeg(x: real): real; /// Переводит градусы в радианы function DegToRad(x: real): real; /// Инициализирует датчик псевдослучайных чисел procedure Randomize; /// Инициализирует датчик псевдослучайных чисел, используя значение seed. При одном и том же seed генерируются одинаковые псевдослучайные последовательности procedure Randomize(seed: integer); /// Возвращает случайное целое в диапазоне от 0 до maxValue-1 function Random(maxValue: integer): integer; /// Возвращает случайное вещественное в диапазоне [0,maxValue) function Random(maxValue: real): real; /// Возвращает случайное целое в диапазоне от a до b function Random(a, b: integer): integer; /// Возвращает случайное вещественное в диапазоне [a,b) function Random(a, b: real): real; /// Возвращает случайное вещественное в диапазоне [a,b] c количеством значащих цифр после точки, равным digits function RandomReal(a, b: real; digits: integer := 2): real; /// Возвращает случайный символ в диапазоне от a до b function Random(a, b: char): char; /// Возвращает случайное целое в диапазоне function Random(diap: IntRange): integer; /// Возвращает случайное вещественное в диапазоне function Random(diap: RealRange): real; /// Возвращает случайный символ в диапазоне function Random(diap: CharRange): char; /// Возвращает случайное вещественное в диапазоне [0..1) function Random: real; /// Возвращает кортеж из двух случайных целых в диапазоне от 0 до maxValue-1 function Random2(maxValue: integer): (integer, integer); /// Возвращает кортеж из двух случайных вещественных в диапазоне [0,maxValue) function Random2(maxValue: real): (real, real); /// Возвращает кортеж из двух случайных целых в диапазоне от a до b function Random2(a, b: integer): (integer, integer); /// Возвращает кортеж из двух случайных символов в диапазоне от a до b function Random2(a, b: char): (char, char); /// Возвращает кортеж из двух случайных вещественных в диапазоне [a,b) function Random2(a, b: real): (real, real); /// Возвращает кортеж из двух случайных целых в диапазоне function Random2(diap: IntRange): (integer, integer); /// Возвращает кортеж из двух случайных символов в диапазоне function Random2(diap: CharRange): (char, char); /// Возвращает кортеж из двух случайных вещественных в диапазоне function Random2(diap: RealRange): (real, real); /// Возвращает кортеж из двух случайных вещественных в диапазоне [0..1) function Random2: (real, real); /// Возвращает кортеж из трех случайных целых в диапазоне от 0 до maxValue-1 function Random3(maxValue: integer): (integer, integer, integer); /// Возвращает кортеж из трех случайных вещественных в диапазоне [0,maxValue) function Random3(maxValue: real): (real, real, real); /// Возвращает кортеж из трех случайных целых в диапазоне от a до b function Random3(a, b: integer): (integer, integer, integer); /// Возвращает кортеж из трех случайных символов в диапазоне от a до b function Random3(a, b: char): (char, char, char); /// Возвращает кортеж из трех случайных вещественных в диапазоне [a,b) function Random3(a, b: real): (real, real, real); /// Возвращает кортеж из трех случайных целых в диапазоне function Random3(diap: IntRange): (integer, integer, integer); /// Возвращает кортеж из трех случайных символов в диапазоне function Random3(diap: CharRange): (char, char, char); /// Возвращает кортеж из трех случайных вещественных в диапазоне function Random3(diap: RealRange): (real, real, real); /// Возвращает кортеж из трех случайных вещественных в диапазоне [0..1) function Random3: (real, real, real); ///-function Max(a: число, b: число): число; /// Возвращает максимальное из чисел a,b function Max(a, b: byte): byte; ///-- function Max(a, b: shortint): shortint; ///-- function Max(a, b: smallint): smallint; ///-- function Max(a, b: word): word; ///-- function Max(a, b: integer): integer; ///-- function Max(a, b: BigInteger): BigInteger; ///-- function Max(a, b: longword): longword; ///-- function Max(a, b: int64): int64; ///-- function Max(a, b: uint64): uint64; ///-- function Max(a, b: real): real; ///-function Min(a: число, b: число): число; /// Возвращает минимальное из чисел a,b function Min(a, b: byte): byte; ///-- function Min(a, b: shortint): shortint; ///-- function Min(a, b: word): word; ///-- function Min(a, b: smallint): smallint; ///-- function Min(a, b: integer): integer; ///-- function Min(a, b: BigInteger): BigInteger; ///-- function Min(a, b: longword): longword; ///-- function Min(a, b: int64): int64; ///-- function Min(a, b: uint64): uint64; ///-- function Min(a, b: real): real; ///-function Min(a,b,...: T): T; /// Возвращает минимальное из a,b,... function Min(params a: array of T): T; ///-- //function Min(params a: array of real): real; ///-- function Min(a, b, c: real): real; ///-- function Min(a, b, c, d: real): real; ///-- function Min(a, b, c: integer): integer; ///-- function Min(a, b, c, d: integer): integer; ///-function Max(a,b,...: T): T; /// Возвращает максимальное из a,b,... function Max(params a: array of T): T; ///-- //function Max(params a: array of real): real; ///-- function Max(a, b, c: real): real; ///-- function Max(a, b, c, d: real): real; ///-- function Max(a, b, c: integer): integer; ///-- function Max(a, b, c, d: integer): integer; ///-function Odd(i: целое): boolean; /// Возвращает True, если i нечетно, и False в противном случае function Odd(i: byte): boolean; ///-- function Odd(i: shortint): boolean; ///-- function Odd(i: word): boolean; ///-- function Odd(i: smallint): boolean; ///-- function Odd(i: integer): boolean; ///-- function Odd(i: BigInteger): boolean; ///-- function Odd(i: longword): boolean; ///-- function Odd(i: int64): boolean; ///-- function Odd(i: uint64): boolean; // ----------------------------------------------------- //>> Подпрограммы для работы с комплексными числами # Functions for Complex numbers // ----------------------------------------------------- /// Конструирует комплексное число с вещественной частью re и мнимой частью im function Cplx(re, im: real): Complex; /// Конструирует комплексное число по полярным координатам function CplxFromPolar(magnitude, phase: real): Complex; /// Возвращает квадратный корень из комплексного числа function Sqrt(c: Complex): Complex; /// Возвращает модуль комплексного числа function Abs(c: Complex): real; /// Возвращает комплексно сопряженное число function Conjugate(c: Complex): Complex; /// Возвращает косинус комплексного числа function Cos(c: Complex): Complex; /// Возвращает экспоненту комплексного числа function Exp(c: Complex): Complex; /// Возвращает натуральный логарифм комплексного числа function Ln(c: Complex): Complex; /// Возвращает натуральный логарифм комплексного числа function Log(c: Complex): Complex; /// Возвращает десятичный логарифм комплексного числа function Log10(c: Complex): Complex; /// Возвращает степень комплексного числа function Power(c, power: Complex): Complex; /// Возвращает синус комплексного числа function Sin(c: Complex): Complex; // ----------------------------------------------------- //>> Подпрограммы для работы со стандартными множествами # Subroutines for set of T // ----------------------------------------------------- ///- procedure Include(var s: set of T; element: T); ///Добавляет элемент element во множество s procedure Include(var s: TypedSet; el: object); ///- procedure Exclude(var s: set of T; element: T); ///Удаляет элемент element из множества s procedure Exclude(var s: TypedSet; el: object); ///- procedure Include(var s: set of T; element: T); ///Добавляет элемент element во множество s procedure Include(var s: NewSet; el: T); ///- procedure Exclude(var s: set of T; element: T); ///Удаляет элемент element из множества s procedure Exclude(var s: NewSet; el: T); procedure Include(var s: NewSet; el: byte); procedure Exclude(var s: NewSet; el: byte); procedure Include(var s: NewSet; el: word); procedure Exclude(var s: NewSet; el: word); procedure Include(var s: NewSet; el: integer); procedure Exclude(var s: NewSet; el: integer); procedure Include(var s: NewSet; el: longword); procedure Exclude(var s: NewSet; el: longword); procedure Include(var s: NewSet; el: shortint); procedure Exclude(var s: NewSet; el: shortint); procedure Include(var s: NewSet; el: smallint); procedure Exclude(var s: NewSet; el: smallint); procedure Include(var s: NewSet; el: int64); procedure Exclude(var s: NewSet; el: int64); procedure Include(var s: NewSet; el: uint64); procedure Exclude(var s: NewSet; el: uint64); // ----------------------------------------------------- //>> Подпрограммы для работы с символами # Subroutines for char // ----------------------------------------------------- /// Увеличивает код символа c на 1 procedure Inc(var c: char); /// Увеличивает код символа c на n procedure Inc(var c: char; n: integer); /// Уменьшает код символа c на 1 procedure Dec(var c: char); /// Уменьшает код символа c на n procedure Dec(var c: char; n: integer); /// Возвращает предшествующий x символ function Pred(x: char): char; // Возвращает символ, отстоящий от x на n позиций назад //function Pred(x: char; n: integer): char; /// Возвращает следующий за x символ function Succ(x: char): char; // Возвращает символ, отстоящий от x на n позиций вперёд //function Succ(x: char; n: integer): char; /// Преобразует код в символ в кодировке Windows function ChrAnsi(a: byte): char; /// Преобразует символ в код в кодировке Windows function OrdAnsi(a: char): byte; /// Преобразует код в символ в кодировке Unicode function Chr(a: word): char; /// Преобразует символ в код в кодировке Unicode function Ord(a: char): word; /// Преобразует код в символ в кодировке Unicode function ChrUnicode(a: word): char; /// Преобразует символ в код в кодировке Unicode function OrdUnicode(a: char): word; /// Преобразует символ в верхний регистр function UpperCase(ch: char): char; /// Преобразует символ в нижний регистр function LowerCase(ch: char): char; /// Преобразует символ в верхний регистр function UpCase(ch: char): char; /// Преобразует символ в нижний регистр function LowCase(ch: char): char; // ----------------------------------------------------- //>> Подпрограммы для работы со строками # Subroutines for string // ----------------------------------------------------- ///-procedure Str(i: целое; var s: string); /// Преобразует целое значение i к строковому представлению и записывает результат в s procedure Str(i: integer; var s: string); ///-- procedure Str(i: longword; var s: string); ///-- procedure Str(i: int64; var s: string); ///-- procedure Str(i: uint64; var s: string); /// Преобразует вещественное значение r к строковому представлению и записывает результат в s procedure Str(r: real; var s: string); /// Преобразует вещественное значение r к строковому представлению и записывает результат в s procedure Str(r: single; var s: string); ///-- procedure Str(s1: string; var s: string); /// Возвращает позицию подстроки subs в строке s. Если не найдена, возвращает 0 function Pos(subs, s: string; from: integer := 1): integer; /// Возвращает позицию подстроки subs в строке s начиная с позиции from. Если не найдена, возвращает 0 function PosEx(subs, s: string; from: integer := 1): integer; /// Возвращает позицию последнего вхождения подстроки subs в строке s. Если не найдена, возвращает 0 function LastPos(subs, s: string): integer; /// Возвращает позицию последнего вхождения подстроки subs в строке s начиная с позиции from. Если не найдена, возвращает 0 function LastPos(subs, s: string; from: integer): integer; /// Возвращает длину строки function Length(s: string): integer; /// Устанавливает длину строки s равной n procedure SetLength(var s: string; n: integer); ///-- procedure SetLengthForShortString(var s: string; n, sz: integer); /// Вставляет подстроку subs в строку s с позиции index procedure Insert(subs: string; var s: string; index: integer); ///-- procedure InsertInShortString(subs: string; var s: string; index, n: integer); /// Удаляет из строки s count символов с позиции index procedure Delete(var s: string; index, count: integer); /// Возвращает подстроку строки s длины count с позиции index function Copy(s: string; index, count: integer): string; ///-function Concat(s1,s2,...): string; /// Возвращает строку, являющуюся результатом слияния строк s1,s2,... function Concat(params strs: array of string): string; /// Возвращает строку, являющуюся результатом слияния строк s1 и s2 function Concat(s1, s2: string): string; /// Возвращает строку в нижнем регистре function LowerCase(s: string): string; /// Возвращает строку в верхнем регистре function UpperCase(s: string): string; /// Возвращает строку, состоящую из count символов ch function StringOfChar(ch: char; count: integer): string; /// Возвращает инвертированную строку function ReverseString(s: string): string; /// Возвращает инвертированную строку в диапазоне длины length начиная с индекса index function ReverseString(s: string; index,length: integer): string; /// Сравнивает строки. Возвращает значение < 0 если s1 0 если s1>s2 и = 0 если s1=s2 function CompareStr(s1, s2: string): integer; /// Возвращает первые count символов строки s function LeftStr(s: string; count: integer): string; /// Возвращает последние count символов строки s function RightStr(s: string; count: integer): string; /// Возвращает строку с удаленными начальными и конечными пробелами function Trim(s: string): string; /// Возвращает строку с удаленными начальными пробелами function TrimLeft(s: string): string; /// Возвращает строку с удаленными конечными пробелами function TrimRight(s: string): string; /// Преобразует строковое представление целого числа к числовому значению function StrToInt(s: string): integer; /// Преобразует строковое представление целого числа к числовому значению function StrToInt64(s: string): int64; /// Преобразует строковое представление вещественного числа к числовому значению function StrToFloat(s: string): real; /// Преобразует строковое представление вещественного числа к числовому значению function StrToFloat(s: string; nfi: NumberFormatInfo): real; /// Преобразует строковое представление вещественного числа к числовому значению function StrToFloat(s: string; DecimalSeparator: string): real; /// Преобразует строковое представление вещественного числа к числовому значению function StrToReal(s: string): real; /// Преобразует строковое представление вещественного числа к числовому значению function StrToReal(s: string; nfi: NumberFormatInfo): real; /// Преобразует строковое представление вещественного числа к числовому значению function StrToReal(s: string; DecimalSeparator: string): real; /// Преобразует строковое представление s целого числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToInt(s: string; var value: integer): boolean; /// Преобразует строковое представление s целого числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToInt64(s: string; var value: int64): boolean; /// Преобразует строковое представление s вещественного числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToFloat(s: string; var value: real): boolean; /// Преобразует строковое представление s вещественного числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToFloat(s: string; var value: single): boolean; /// Преобразует строковое представление s вещественного числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToReal(s: string; var value: real): boolean; /// Преобразует строковое представление s вещественного числа к числовому значению и записывает его в value. ///При невозможности преобразования возвращается False function TryStrToSingle(s: string; var value: single): boolean; /// Считывает целое из строки начиная с позиции from и устанавливает from за считанным значением function ReadIntegerFromString(s: string; var from: integer): integer; /// Считывает вещественное из строки начиная с позиции from и устанавливает from за считанным значением function ReadRealFromString(s: string; var from: integer): real; /// Считывает из строки последовательность символов до пробельного символа начиная с позиции from и устанавливает from за считанным значением function ReadWordFromString(s: string; var from: integer): string; /// Возвращает True если достигнут конец строки или в строке остались только пробельные символы и False в противном случае function StringIsEmpty(s: string; var from: integer): boolean; /// Считывает целое из строки начиная с позиции from и устанавливает from за считанным значением. ///Возвращает True если считывание удачно и False в противном случае function TryReadIntegerFromString(s: string; var from: integer; var res: integer): boolean; /// Считывает вещественное из строки начиная с позиции from и устанавливает from за считанным значением. ///Возвращает True если считывание удачно и False в противном случае function TryReadRealFromString(s: string; var from: integer; var res: real): boolean; ///-procedure Val(s: string; var value: число; var err: integer); /// Преобразует строковое представление s целого или вещественного числа к числовому значению и записывает его в переменную value. ///Если преобразование успешно, то err=0, иначе err>0 procedure Val(s: string; var value: integer; var err: integer); ///-- procedure Val(s: string; var value: shortint; var err: integer); ///-- procedure Val(s: string; var value: smallint; var err: integer); ///-- procedure Val(s: string; var value: int64; var err: integer); ///-- procedure Val(s: string; var value: byte; var err: integer); ///-- procedure Val(s: string; var value: word; var err: integer); ///-- procedure Val(s: string; var value: longword; var err: integer); ///-- procedure Val(s: string; var value: uint64; var err: integer); ///-- procedure Val(s: string; var value: real; var err: integer); ///-- procedure Val(s: string; var value: single; var err: integer); /// Преобразует целое число к строковому представлению function IntToStr(a: integer): string; /// Преобразует целое число к строковому представлению function IntToStr(a: int64): string; /// Преобразует вещественное число к строковому представлению function FloatToStr(a: real): string; /// Преобразует вещественное число к строковому представлению function FloatToStr(a: real; nfi: NumberFormatInfo): string; /// Возвращает отформатированную строку, построенную по форматной строке и списку форматируемых параметров function Format(formatstring: string; params pars: array of object): string; // ----------------------------------------------------- //>> Общие подпрограммы # Common subroutines // ----------------------------------------------------- /// Увеличивает значение переменной i на 1 procedure Inc(var i: integer); /// Увеличивает значение переменной i на n procedure Inc(var i: integer; n: integer); /// Уменьшает значение переменной i на 1 procedure Dec(var i: integer); /// Уменьшает значение переменной i на n procedure Dec(var i: integer; n: integer); ///-procedure Inc(var e: перечислимый тип); /// Увеличивает значение перечислимого типа на 1 procedure Inc(var b: byte); ///-procedure Inc(var e: перечислимый тип; n: integer); /// Увеличивает значение перечислимого типа на n procedure Inc(var b: byte; n: integer); ///-procedure Dec(var e: перечислимый тип); /// Уменьшает значение перечислимого типа на 1 procedure Dec(var b: byte); ///-procedure Dec(var e: перечислимый тип; n: integer); /// Уменьшает значение перечислимого типа на n procedure Dec(var b: byte; n: integer); ///-- procedure Inc(var f: boolean); ///-- procedure Dec(var f: boolean); ///-function Ord(a: целое): целое; /// Возвращает порядковый номер значения a function Ord(a: integer): integer; ///-function Ord(a: перечислимый тип): integer; /// Возвращает порядковый номер значения a function Ord(a: longword): longword; ///-- function Ord(a: int64): int64; ///-- function Ord(a: uint64): uint64; ///-- function Ord(a: boolean): integer; ///-function Succ(x: целое): целое; /// Возвращает следующее за x значение function Succ(x: integer): integer; ///-function Succ(x: перечислимый тип): перечислимый тип; /// Возвращает следующее за x значение function Succ(x: byte): byte; ///-- function Succ(x: shortint): shortint; ///-- function Succ(x: smallint): smallint; ///-- function Succ(x: word): word; ///-- function Succ(x: longword): longword; ///-- function Succ(x: int64): int64; ///-- function Succ(x: uint64): uint64; ///-- function Succ(x: boolean): boolean; ///-function Pred(x: целое): целое; /// Возвращает предшествующее x значение function Pred(x: integer): integer; ///-function Pred(x: перечислимый тип): перечислимый тип; /// Возвращает предшествующее x значение function Pred(x: byte): byte; ///-- function Pred(x: shortint): shortint; ///-- function Pred(x: smallint): smallint; ///-- function Pred(x: word): word; ///-- function Pred(x: longword): longword; ///-- function Pred(x: int64): int64; ///-- function Pred(x: uint64): uint64; ///-- function Pred(x: boolean): boolean; /// Возвращает True, если значение val находится между a и b включительно function InRange(val, a, b: T): boolean; where T: IComparable; /// Возвращает True, если значение val находится между a и b (включительно) независимо от порядка a и b function Between(val, a, b: T): boolean; where T: IComparable; /// Меняет местами значения двух переменных procedure Swap(var a, b: T); /// Возвращает True, если достигнут конец строки function Eoln: boolean; /// Возвращает True, если достигнут конец потока ввода function Eof: boolean; /// Пропускает пробельные символы, после чего возвращает True, если достигнут конец потока ввода function SeekEof: boolean; /// Пропускает пробельные символы, после чего возвращает True, если достигнут конец строки function SeekEoln: boolean; /// Возвращает аргумены командой строки, с которыми была запущена программа function CommandLineArgs: array of string; /// Преобразует объект в строковое представление function ObjectToString(obj: object): string; // ----------------------------------------------------- //>> Подпрограммы для работы с динамическими массивами # Subroutines for array of T // ----------------------------------------------------- ///- function Low(a: array of T): integer; /// Возвращает 0 function Low(i: System.Array): integer; ///- function High(a: array of T): integer; /// Возвращает верхнюю границу динамического массива function High(i: System.Array): integer; ///- function Length(a: array of T): integer; /// Возвращает длину динамического массива function Length(a: System.Array): integer; ///- function Length(a: array of T; dim: integer): integer; /// Возвращает длину динамического массива по размерности dim function Length(a: System.Array; dim: integer): integer; ///- procedure SetLength(var a: array of T; n: integer); /// Устанавливает длину одномерного динамического массива. Старое содержимое сохраняется //procedure SetLength(var a: array of T; n: integer); ///- procedure SetLength(var a: array [,...,] of T; n1,n2,...: integer); /// Устанавливает размеры n-мерного динамического массива. Старое содержимое сохраняется //procedure SetLength(var a: array[,...,] of T; n: integer); ///- function Copy(a: array of T): array of T; /// Создаёт копию динамического массива function Copy(a: System.Array): System.Array; /// Сортирует динамический массив по возрастанию procedure Sort(a: array of T); /// Сортирует динамический массив по возрастанию procedure Sort(a: array of string); /// Сортирует динамический массив по критерию сортировки, задаваемому функцией сравнения cmp procedure Sort(a: array of T; cmp: (T,T)->integer); /// Сортирует динамический массив по критерию сортировки, задаваемому функцией сравнения less procedure Sort(a: array of T; less: (T,T)->boolean); /// Сортирует динамический массив по ключу procedure Sort(a: array of T; keySelector: T->TKey); /// Сортирует динамический массив по ключу procedure Sort(a: array of T; keySelector: T->string); /// Сортирует список по возрастанию procedure Sort(l: List); /// Сортирует список по возрастанию procedure Sort(var l: List); /// Сортирует список по критерию сортировки, задаваемому функцией сравнения cmp procedure Sort(l: List; cmp: (T,T)->integer); /// Сортирует список по критерию сортировки, задаваемому функцией сравнения less procedure Sort(l: List; less: (T,T)->boolean); /// Сортирует список по возрастанию по ключу procedure Sort(var l: List; keySelector: T->T1); /// Сортирует список по возрастанию по ключу procedure Sort(var l: List; keySelector: T->string); /// Сортирует динамический массив по убыванию procedure SortDescending(a: array of T); /// Сортирует динамический массив по убыванию procedure SortDescending(a: array of string); /// Сортирует динамический массив по убыванию по ключу procedure SortDescending(var a: array of T; keySelector: T->T1); /// Сортирует динамический массив по убыванию по ключу procedure SortDescending(var a: array of T; keySelector: T->string); /// Сортирует список по убыванию procedure SortDescending(l: List); /// Сортирует список по убыванию procedure SortDescending(var l: List); /// Сортирует список по убыванию по ключу procedure SortDescending(var l: List; keySelector: T->T1); /// Сортирует список по убыванию по ключу procedure SortDescending(var l: List; keySelector: T->string); /// Изменяет порядок элементов в динамическом массиве на противоположный procedure Reverse(a: array of T); /// Изменяет порядок элементов на противоположный в диапазоне динамического массива длины count, начиная с индекса index procedure Reverse(a: array of T; index, count: integer); /// Изменяет порядок элементов в списке на противоположный procedure Reverse(a: List); /// Изменяет порядок элементов на противоположный в диапазоне списка длины count, начиная с индекса index procedure Reverse(a: List; index, count: integer); /// Изменяет порядок символов в строке на противоположный procedure Reverse(var s: string); /// Изменяет порядок символов в части строки длины count на противоположный, начиная с индекса index procedure Reverse(var s: string; index, count: integer); /// Перемешивает динамический массив случайным образом procedure Shuffle(a: array of T); /// Возвращает, совпадают ли массивы function ArrEqual(a, b: array of T): boolean; /// Сравнивает матрицы на равенство function MatrEqual(a, b: array [,] of T): boolean; /// Перемешивает список случайным образом procedure Shuffle(l: List); /// Возвращает следующую перестановку в массиве function NextPermutation(a: array of integer): boolean; // ----------------------------------------------------- //>> Подпрограммы для генерации последовательностей # Subroutines for sequence generation // ----------------------------------------------------- /// Возвращает последовательность целых от a до b function Range(a, b: integer): sequence of integer; /// Возвращает последовательность целых от a до b с шагом step function Range(a, b, step: integer): sequence of integer; /// Возвращает последовательность длинных целых от a до b function Range(a, b: BigInteger): sequence of BigInteger; /// Возвращает последовательность длинных целых от a до b с шагом step function Range(a, b, step: BigInteger): sequence of BigInteger; /// Возвращает последовательность символов от c1 до c2 function Range(c1, c2: char): sequence of char; /// Возвращает последовательность символов от c1 до c2 с шагом step function Range(c1, c2: char; step: integer): sequence of char; /// Возвращает последовательность вещественных от a до b с шагом step function Range(a, b, step: real): sequence of real; /// Возвращает последовательность вещественных в точках разбиения отрезка [a,b] на n равных частей function PartitionPoints(a, b: real; n: integer): sequence of real; /// Возвращает последовательность указанных элементов function Seq(params a: array of T): sequence of T; /// Возвращает последовательность из n случайных целых элементов function SeqRandom(n: integer := 10; a: integer := 0; b: integer := 100): sequence of integer; /// Возвращает последовательность из n случайных целых элементов function SeqRandomInteger(n: integer := 10; a: integer := 0; b: integer := 100): sequence of integer; /// Возвращает последовательность из n случайных вещественных элементов function SeqRandomReal(n: integer := 10; a: real := 0; b: real := 10; digits: integer := 1): sequence of real; /// Возвращает последовательность из count элементов, заполненных значениями f(i) function SeqGen(count: integer; f: integer->T): sequence of T; /// Возвращает последовательность из count элементов, заполненных значениями f(i), начиная с i=from function SeqGen(count: integer; f: integer->T; from: integer): sequence of T; /// Возвращает последовательность из count элементов, начинающуюся с first, с функцией next перехода от предыдущего к следующему function SeqGen(count: integer; first: T; next: T->T): sequence of T; /// Возвращает последовательность из count элементов, начинающуюся с first и second, ///с функцией next перехода от двух предыдущих к следующему function SeqGen(count: integer; first, second: T; next: (T,T) ->T): sequence of T; /// Возвращает последовательность элементов с начальным значением first, ///функцией next перехода от предыдущего к следующему и условием pred продолжения последовательности function SeqWhile(first: T; next: T->T; pred: T->boolean): sequence of T; /// Возвращает последовательность элементов, начинающуюся с first и second, ///с функцией next перехода от двух предыдущих к следующему и условием pred продолжения последовательности function SeqWhile(first, second: T; next: (T,T) ->T; pred: T->boolean): sequence of T; /// Возвращает последовательность из count элементов x function SeqFill(count: integer; x: T): sequence of T; /// Возвращает бесконечную рекуррентную последовательность элементов, задаваемую начальным элементом first и функцией next function Iterate(first: T; next: T->T): sequence of T; /// Объединяет две последовательности в последовательность двухэлементных кортежей function Zip(a: sequence of T; b: sequence of T1): sequence of (T, T1); /// Объединяет три последовательности в последовательность трехэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2); /// Объединяет четыре последовательности в последовательность четырехэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3); /// Объединяет пять последовательностей в последовательность пятиэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4); /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; fun: (T,T1) -> TRes): sequence of TRes; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; fun: (T,T1,T2) -> TRes): sequence of TRes; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; fun: (T,T1,T2,T3) -> TRes): sequence of TRes; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; fun: (T,T1,T2,T3,T4) -> TRes): sequence of TRes; /// Возвращает декартово произведение последовательностей, проектируя каждую пару на значение function Cartesian(a: sequence of T; b: sequence of T1; func: (T,T1)->TRes): sequence of TRes; /// Возвращает декартово произведение последовательностей, проектируя каждую тройку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; func: (T,T1,T2)->TRes): sequence of TRes; /// Возвращает декартово произведение последовательностей, проектируя каждую четвёрку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; func: (T,T1,T2,T3)->TRes): sequence of TRes; /// Возвращает декартово произведение последовательностей, проектируя каждую пятёрку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; func: (T,T1,T2,T3,T4)->TRes): sequence of TRes; /// Возвращает декартово произведение последовательностей в виде последовательности пар function Cartesian(a: sequence of T; b: sequence of T1): sequence of (T, T1); /// Возвращает декартово произведение последовательностей в виде последовательности троек function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2); /// Возвращает декартово произведение последовательностей в виде последовательности четвёрок function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3); /// Возвращает декартово произведение последовательностей в виде последовательности пятёрок function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4); /// Возвращает последовательность из n целых, введенных с клавиатуры function ReadSeqInteger(n: integer): sequence of integer; /// Возвращает последовательность из n вещественных, введенных с клавиатуры function ReadSeqReal(n: integer): sequence of real; /// Возвращает последовательность из n строк, введенных с клавиатуры function ReadSeqString(n: integer): sequence of string; /// Выводит приглашение к вводу и возвращает последовательность из n целых, введенных с клавиатуры function ReadSeqInteger(prompt: string; n: integer): sequence of integer; /// Выводит приглашение к вводу и возвращает последовательность из n вещественных, введенных с клавиатуры function ReadSeqReal(prompt: string; n: integer): sequence of real; /// Выводит приглашение к вводу и возвращает последовательность из n строк, введенных с клавиатуры function ReadSeqString(prompt: string; n: integer): sequence of string; /// Возвращает последовательность целых, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqIntegerWhile(cond: integer->boolean): sequence of integer; /// Возвращает последовательность вещественных, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqRealWhile(cond: real->boolean): sequence of real; /// Возвращает последовательность строк, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqStringWhile(cond: string->boolean): sequence of string; /// Выводит приглашение к вводу и возвращает последовательность целых, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqIntegerWhile(prompt: string; cond: integer->boolean): sequence of integer; /// Выводит приглашение к вводу и возвращает последовательность вещественных, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqRealWhile(prompt: string; cond: real->boolean): sequence of real; /// Выводит приглашение к вводу и возвращает последовательность строк, вводимых с клавиатуры пока выполняется определенное условие function ReadSeqStringWhile(prompt: string; cond: string->boolean): sequence of string; // ----------------------------------------------------- //>> Подпрограммы для создания динамических массивов # Subroutines for array of T generation // ----------------------------------------------------- /// Возвращает массив, заполненный указанными значениями function Arr(params a: array of T): array of T; /// Возвращает массив, заполненный значениями из последовательнсти function Arr(a: sequence of T): array of T; /// Возвращает массив, заполненный диапазоном значений function Arr(a: IntRange): array of integer; /// Возвращает массив, заполненный диапазоном значений function Arr(a: CharRange): array of char; /// Возвращает массив размера n, заполненный случайными целыми значениями function ArrRandom(n: integer := 10; a: integer := 0; b: integer := 100): array of integer; /// Возвращает массив размера n, заполненный случайными целыми значениями в диапазоне от a до b function ArrRandomInteger(n: integer; a: integer; b: integer): array of integer; /// Возвращает массив размера n, заполненный случайными целыми значениями function ArrRandomInteger(n: integer := 10): array of integer; /// Возвращает массив размера n, заполненный случайными вещественными значениями в диапазоне от a до b function ArrRandomReal(n: integer; a: real; b: real; digits: integer := 2): array of real; /// Возвращает массив размера n, заполненный случайными вещественными значениями function ArrRandomReal(n: integer := 10; digits: integer := 2): array of real; /// Возвращает массив из count элементов, заполненных значениями gen(i) function ArrGen(count: integer; gen: integer->T): array of T; /// Возвращает массив из count элементов, заполненных значениями gen(i), начиная с i=from function ArrGen(count: integer; gen: integer->T; from: integer): array of T; /// Возвращает массив из count элементов, начинающихся с first, с функцией next перехода от предыдущего к следующему function ArrGen(count: integer; first: T; next: T->T): array of T; /// Возвращает массив из count элементов, начинающихся с first и second, с функцией next перехода от двух предыдущих к следующему function ArrGen(count: integer; first, second: T; next: (T,T) ->T): array of T; /// Возвращает массив из count элементов x function ArrFill(count: integer; x: T): array of T; // Возвращает массив из элементов массива a, удовлетворяющих условию condition // a.FindAll //function ArrFilter(a: array of T; condition: T->boolean): array of T; // Возвращает по массиву a массив, преобразованный по правилу convert // a.ConvertAll //function ArrTransform(a: array of T; convert: T->T1): array of T1; /// Возвращает массив из n целых, введенных с клавиатуры function ReadArrInteger(n: integer): array of integer; /// Возвращает массив из n целых int64, введенных с клавиатуры function ReadArrInt64(n: integer): array of int64; /// Возвращает массив из n вещественных, введенных с клавиатуры function ReadArrReal(n: integer): array of real; /// Возвращает массив из n строк, введенных с клавиатуры function ReadArrString(n: integer): array of string; ///-- function ReadArrInteger: array of integer; ///-- function ReadArrReal: array of real; ///-- function ReadArrString: array of string; /// Выводит приглашение к вводу и возвращает массив из n целых, введенных с клавиатуры function ReadArrInteger(prompt: string; n: integer): array of integer; /// Выводит приглашение к вводу и возвращает массив из n вещественных, введенных с клавиатуры function ReadArrReal(prompt: string; n: integer): array of real; /// Выводит приглашение к вводу и возвращает массив из n строк, введенных с клавиатуры function ReadArrString(prompt: string; n: integer): array of string; // ----------------------------------------------------- //>> Подпрограммы для создания двумерных динамических массивов # Subroutines for matrixes // ----------------------------------------------------- /// Возвращает двумерный массив размера m x n, заполненный указанными значениями по строкам function Matr(m,n: integer; params data: array of T): array [,] of T; /// Возвращает двумерный массив, заполненный значениями из одномерных массивов function Matr(params aa: array of array of T): array [,] of T; /// Генерирует двумерный массив по массиву массивов строк function MatrByRow(a: array of array of T): array [,] of T; /// Генерирует двумерный массив по последовательности массивов строк function MatrByRow(a: sequence of array of T): array [,] of T; /// Генерирует двумерный массив по последовательности последовательностей строк function MatrByRow(a: sequence of sequence of T): array [,] of T; /// Генерирует двумерный массив по строкам из последовательности function MatrByRow(m,n: integer; a: sequence of T): array [,] of T; /// Генерирует двумерный массив по массиву массивов столбцов function MatrByCol(a: array of array of T): array [,] of T; /// Генерирует двумерный массив по последовательности массивов столбцов function MatrByCol(a: sequence of array of T): array [,] of T; /// Генерирует двумерный массив по последовательности последовательностей столбцов function MatrByCol(a: sequence of sequence of T): array [,] of T; /// Генерирует двумерный массив по столбцам из последовательности function MatrByCol(m,n: integer; a: sequence of T): array [,] of T; /// Возвращает матрицу m на n целых, введенных с клавиатуры function ReadMatrInteger(m, n: integer): array [,] of integer; /// Возвращает матрицу m на n вещественных, введенных с клавиатуры function ReadMatrReal(m, n: integer): array [,] of real; /// Возвращает двумерный массив размера m x n, заполненный случайными целыми значениями function MatrRandom(m: integer := 5; n: integer := 5; a: integer := 0; b: integer := 100): array [,] of integer; /// Возвращает двумерный массив размера m x n, заполненный случайными целыми значениями function MatrRandomInteger(m: integer := 5; n: integer := 5; a: integer := 0; b: integer := 100): array [,] of integer; /// Возвращает двумерный массив размера m x n, заполненный случайными вещественными значениями function MatrRandomReal(m: integer := 5; n: integer := 5; a: real := 0; b: real := 10; digits: integer := 2): array [,] of real; /// Возвращает двумерный массив размера m x n, заполненный элементами gen(i,j) function MatrGen(m, n: integer; gen: (integer,integer)->T): array [,] of T; /// Возвращает двумерный массив размера m x n, заполненный элементами x function MatrFill(m, n: integer; x: T): array [,] of T; /// Транспонирует двумерный массив function Transpose(a: array [,] of T): array [,] of T; // ----------------------------------------------------- //>> Подпрограммы для создания кортежей # Subroutines for tuple generation // ----------------------------------------------------- ///- function Rec(x1: T1, x2: T2,...): (T1,T2,...); /// Возвращает кортеж из элементов разных типов function Rec(x1: T1; x2: T2): System.Tuple; ///-- function Rec(x1: T1; x2: T2; x3: T3): (T1, T2, T3); ///-- function Rec(x1: T1; x2: T2; x3: T3; x4: T4): (T1, T2, T3, T4); ///-- function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5): (T1, T2, T3, T4, T5); ///-- function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5; x6: T6): (T1, T2, T3, T4, T5, T6); ///-- function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5; x6: T6; x7: T7): (T1, T2, T3, T4, T5, T6, T7); ///-- //function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5; x6: T6; x7: T7; x8: T8): (T1, T2, T3, T4, T5, T6, T7); // ----------------------------------------------------- //>> Короткие функции Lst, LLst, HSet, SSet, Dict, KV # Short functions Lst, HSet, SSet, Dict, KV // ----------------------------------------------------- /// Возвращает список, заполненный указанными значениями function Lst(params a: array of T): List; /// Возвращает список, заполненный значениями из последовательности function Lst(a: sequence of T): List; /// Возвращает список, заполненный диапазоном значений function Lst(a: IntRange): List; /// Возвращает список, заполненный диапазоном значений function Lst(a: CharRange): List; /// Возвращает список, заполненный указанными целыми значениями function LstStr(params a: array of string): List; /// Возвращает список, заполненный указанными целыми значениями function LstInt(params a: array of integer): List; /// Возвращает двусвязный список, заполненный указанными значениями function LLst(params a: array of T): LinkedList; /// Возвращает двусвязный список, заполненный значениями из последовательности function LLst(a: sequence of T): LinkedList; /// Возвращает множество на базе хеш таблицы, заполненное указанными значениями function HSet(params a: array of T): HashSet; /// Возвращает множество на базе хеш таблицы, заполненное значениями из последовательности function HSet(a: sequence of T): HashSet; /// Возвращает множество на базе хеш таблицы, заполненное диапазоном значений function HSet(a: IntRange): HashSet; /// Возвращает множество на базе хеш таблицы, заполненное заполненный диапазоном значений function HSet(a: CharRange): HashSet; /// Возвращает множество на базе хеш таблицы, заполненное целыми значениями function HSetInt(params a: array of integer): HashSet; /// Возвращает множество на базе хеш таблицы, заполненное строковыми значениями function HSetStr(params a: array of string): HashSet; /// Возвращает множество, заполненное указанными значениями function SetOf(params a: array of T): NewSet; /// Возвращает множество на базе бинарного дерева поиска, заполненное указанными значениями function SSet(params a: array of T): SortedSet; /// Возвращает множество на базе бинарного дерева поиска, заполненное значениями из последовательности function SSet(a: sequence of T): SortedSet; /// Возвращает множество на базе бинарного дерева поиска, заполненное целыми значениями function SSetInt(params a: array of integer): SortedSet; /// Возвращает множество на базе бинарного дерева поиска, заполненное строковыми значениями function SSetStr(params a: array of string): SortedSet; /// Возвращает словарь пар элементов (ключ, значение) function Dict(params pairs: array of KeyValuePair): Dictionary; /// Возвращает словарь пар элементов (ключ, значение) function Dict(params pairs: array of (TKey, TVal)): Dictionary; /// Возвращает словарь пар элементов (ключ, значение), построенный по последовательности пар function Dict(pairs: sequence of KeyValuePair): Dictionary; /// Возвращает словарь пар элементов (ключ, значение), построенный по последовательности пар function Dict(pairs: sequence of (TKey, TVal)): Dictionary; /// Возвращает словарь пар элементов (ключ, значение), построенный по последовательностям ключей и значений function Dict(keys: sequence of TKey; values: sequence of TVal): Dictionary; /// Возвращает пару элементов (ключ, значение) function KV(key: TKey; value: TVal): KeyValuePair; /// Возвращает пару элементов (ключ, значение) function Pair(key: TKey; value: TVal): KeyValuePair; /// Возвращает словарь пар элементов (строка, строка) function DictStr(params pairs: array of (string, string)): Dictionary; /// Возвращает словарь пар элементов (строка, целое) function DictStrInt(params pairs: array of (string, integer)): Dictionary; /// Возвращает словарь пар элементов (целое, целое) function DictInt(params pairs: array of (integer, integer)): Dictionary; //{{{--doc: Конец секции интерфейса для документации }}} // ----------------------------------------------------- //>> Вспомогательные функции для pattern matching # // ----------------------------------------------------- ///-- function __TypeCheckAndAssignForIsMatch(obj: object; var res: T): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; ///-- function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; // Вспомогательные функции для a..b ///-- function InRangeInternal(x: integer; a,b: integer): boolean; ///-- function InRangeInternal(x: real; a,b: real): boolean; ///-- function InRangeInternal(x: char; a,b: char): boolean; // ----------------------------------------------------- // Стандартные классы исключений // ----------------------------------------------------- type ///Базовый класс для исключений, бросаемых при создании инстанции generic-типа BadGenericInstanceParameterException = class(Exception) protected InstanceType: System.Type; public constructor Create(ActualParameterType: System.Type); end; ///Бросается если тип непригоден для указателей CanNotUseTypeForPointersException = class(BadGenericInstanceParameterException) public function ToString: string; override; end; ///Бросается если тип непригоден для типизированных файлов CanNotUseTypeForTypedFilesException = class(BadGenericInstanceParameterException) public function ToString: string; override; end; ///Бросается если тип непригоден для бинарных файлов CanNotUseTypeForFilesException = class(BadGenericInstanceParameterException) public function ToString: string; override; end; RangeException = class(SystemException) end; CommandLineArgumentOutOfRangeException = class(SystemException) end; // ----------------------------------------------------- // Общедоступные переменные // ----------------------------------------------------- var /// Содержит аргумены командой строки, с которыми была запущена программа _CommandLineArgs: array of string := nil; /// Стандартный текстовый файл для вывода. Связывается процедурой Assign с файлом на диске, после чего весь вывод на консоль перенаправляется в этот файл output: TextFile; /// Стандартный текстовый файл для ввода. Связывается процедурой Assign с файлом на диске, после чего весь ввод с консоли перенаправляется из этого файла input: TextFile; /// Стандартный текстовый файл ошибок. Связывается процедурой Assign с файлом на диске, после чего весь вывод с использованием ErrOutput перенаправляется в этот файл ErrOutput: TextFile; /// Определяет текущую систему ввода-вывода CurrentIOSystem: IOSystem; /// Принимает значение True, если приложение имеет консольное окно IsConsoleApplication: boolean; ///-- RedirectIOInDebugMode := False; ///-- ExecuteBeforeProcessTerminateIn__Mode: procedure(e: Exception); //GCHandlersForReferencePointers := new GCHandlersController; ///-- ExitCode := 0; // TODO Сделать возврат в Main ///-- DefaultEncoding: Encoding; ///-- PrintDelimDefault: string := ' '; ///-- PrintMatrixWithFormat: boolean := True; var ///-- __CONFIG__: Dictionary := new Dictionary; // Вспомогательные подпрограммы. Из раздела интерфейса не убирать!!! // ----------------------------------------------------- // Internal System subprograms // ----------------------------------------------------- ///-- function CopyWithSize(source, dest: &Array): &Array; ///-- function check_in_range(val: int64; low, up: int64): int64; ///-- function check_in_range_char(val: char; low, up: char): char; ///-- function RunTimeSizeOf(t: System.Type): integer; ///-- function GetCharInShortString(s: string; ind, n: integer): char; ///-- function SetCharInShortString(s: string; ind, n: integer; c: char): string; ///-- function ClipShortString(s: string; len: integer): string; ///-- function GetResourceStream(ResourceFileName: string): Stream; ///-- function FormatValue(value: object; NumOfChars: integer): string; ///-- function FormatValue(value: integer; NumOfChars: integer): string; ///-- function FormatValue(value: int64; NumOfChars: integer): string; ///-- function FormatValue(value: real; NumOfChars: integer): string; ///-- function FormatValue(value: real; NumOfChars, NumOfSignesAfterDot: integer): string; ///-- procedure StringDefaultPropertySet(var s: string; index: integer; c: char); //procedure InitShortString(var s: ShortString; Length: integer); ///Проверяет возможность использования указателей на тип T procedure CheckCanUsePointerOnType(T: System.Type); ///Проверяет возможность записи типа T в файл procedure CheckCanUseTypeForBinaryFiles(T: System.Type); ///Проверяет возможность создания file of T procedure CheckCanUseTypeForTypedFiles(T: System.Type); ///Определяет специальные типы function RuntimeDetermineType(T: System.Type): byte; ///Возвращает объект класса в зависимости от значения kind function RuntimeInitialize(kind: byte; variable: object): object; ///Вычисление размера типа на этапе выполнения function GetRuntimeSize: integer; function IsUnix: boolean; ///-- function ExecuteAssemlyIsDll: boolean; ///-- function __StandardFilesDirectory: string; ///-- function __FindFile(fileName: string): string; ///-- function __FixPointer(obj: object): GCHandle; // ----------------------------------------------------- // Internal for OpenMPSupport // ----------------------------------------------------- ///-- procedure omp_set_nested(nested: integer); ///-- function omp_get_nested: integer; ///-- var OMP_NESTED: boolean := false; // ----------------------------------------------------- // Internal typed sets operations // ----------------------------------------------------- ///-- function Union(s1, s2: TypedSet): TypedSet; ///-- function Subtract(s1, s2: TypedSet): TypedSet; ///-- function Intersect(s1, s2: TypedSet): TypedSet; ///-- function CreateSet(params elems: array of object): TypedSet; ///-- function CreateSet: TypedSet; ///-- function CreateBoundedSet(low, high: object): TypedSet; ///-- function InSet(obj: object; s: TypedSet): boolean; ///-- function CreateDiapason(low, high: integer): Diapason; ///-- function CreateObjDiapason(low, high: object): Diapason; ///-- function CompareSetEquals(s1, s2: TypedSet): boolean; ///-- function CompareSetInEquals(s1, s2: TypedSet): boolean; ///-- function CompareSetLess(s1, s2: TypedSet): boolean; ///-- function CompareSetGreaterEqual(s1, s2: TypedSet): boolean; ///-- function CompareSetLessEqual(s1, s2: TypedSet): boolean; ///-- function CompareSetGreater(s1, s2: TypedSet): boolean; ///-- procedure ClipSet(var s: TypedSet; low, high: object); ///-- procedure AssignSet(var left: TypedSet; right: TypedSet); ///-- function ClipSetFunc(s: TypedSet; low, high: object): TypedSet; ///-- function ClipShortStringInSet(s: TypedSet; len: integer): TypedSet; ///-- procedure ClipShortStringInSetProcedure(var s: TypedSet; len: integer); ///-- procedure AssignSetWithBounds(var left: TypedSet; right: TypedSet; low, high: object); ///-- procedure TypedSetInit(var st: TypedSet); ///-- procedure TypedSetInitWithBounds(var st: TypedSet; low, high: object); ///-- procedure TypedSetInitWithShortString(var st: TypedSet; len: integer); // ----------------------------------------------------- // Internal classes // ----------------------------------------------------- type ///-- GCHandlersController = class(System.Collections.IEnumerable) private Counters, Handlers: Hashtable; public constructor; procedure Add(obj: Object); procedure Remove(obj: Object); function GetCounter(obj: Object): integer; function GetEnumerator: System.Collections.IEnumerator; end; type ///-- PointerOutput = class public p: pointer; function ToString: string; override; constructor(ptr: pointer); end; type ///-- __ConceptSingleton = class where T: constructor; class _instance: T; class inited: boolean := false; public class function Instance: T; begin if inited = false then begin inited := true; _instance := new T; end; Result := _instance; end; end; {type ///-- __TypeclassRestrictedFunctionAttribute = class(Attribute) public constructor; begin end; end; ///-- __TypeclassGenericParameterAttribute = class(Attribute) public constructor(instanceName: string); begin end; end; ///-- __TypeclassAttribute = class(Attribute) public constructor(typeclassName: string); begin end; end; ///-- __TypeclassMemberAttribute = class(Attribute) public constructor; begin end; end; ///-- __TypeclassInstanceAttribute = class(Attribute) public constructor(instanceName: string); begin end; end;} type // Смысл полей Num, Width и Fmt соответствует // атрибутам форматирования {Num,Width:Fmt}. // Поле Comment может интерпретироваться как // дополнительная строка, приписываемая слева к свойству. // Если для первого атрибута дополнительная строка // начинается со скобок или кавычек, то парные символы // добавляются в конец итоговой строки. /// Класс атрибута форматирования текста PrintAttribute = class(System.Attribute) public Comment: string; Num: integer; Width: integer; Fmt: string; constructor (n: integer) := (Comment, Num, Width, Fmt) := ('', n, 0, ''); constructor (n, w: integer) := (Comment, Num, Width, Fmt) := ('', n, w, ''); constructor (n: integer; f: string) := (Comment, Num, Width, Fmt) := ('', n, 0, f); constructor (n, w: integer; f: string) := (Comment, Num, Width, Fmt) := ('', n, w, f); constructor (c: string; n: integer) := (Comment, Num, Width, Fmt) := (c, n, 0, ''); constructor (c: string; n, w: integer) := (Comment, Num, Width, Fmt) := (c, n, w, ''); constructor (c: string; n: integer; f: string) := (Comment, Num, Width, Fmt) := (c, n, 0, f); constructor (c: string; n, w: integer; f: string) := (Comment, Num, Width, Fmt) := (c, n, w, f); end; type [AttributeUsage(AttributeTargets.Class)] PCUNotRestoreAttribute = class(System.Attribute) public constructor := exit; end; type [AttributeUsage(AttributeTargets.Class or AttributeTargets.Method or AttributeTargets.Property or AttributeTargets.Interface or AttributeTargets.Field or AttributeTargets.Struct)] PCUAlwaysRestoreAttribute = class(System.Attribute) public constructor := exit; end; ///-- function InternalRange(l,r: integer): IntRange; ///-- function InternalRange(l,r: char): CharRange; ///-- function InternalRange(l,r: real): RealRange; ///-- function IsInputPipedOrRedirectedFromFile: boolean; ///-- function CheckAndCorrectFromToAndCalcCountForSystemSlice(situation: integer; Len: integer; var from, &to: integer; step: integer): integer; type ///-- ZeroStepException = class(exception) constructor Create; end; // ----------------------------------------------------- // Internal procedures for PABCRTL.dll // ----------------------------------------------------- ///-- procedure __InitModule__; ///-- procedure __InitPABCSystem; ///-- procedure __FinalizeModule__; // ----------------------------------------------------- // DQNToNullable for dot_question_node // ----------------------------------------------------- function DQNToNullable(v: T): Nullable; where T: record; implementation function NewSet.ToString: string := $'{ObjectToString(hs)}'; var rnd: System.Random; nfi: NumberFormatInfo; StartTime: DateTime;// Для Milliseconds const WRITELN_IN_BINARYFILE_ERROR_MESSAGE = 'Операция Writeln не применима к бинарным файлам!!Writeln is not applicable to binary files'; InternalNullBasedArrayName = 'NullBasedArray'; FILE_NOT_ASSIGNED = 'Для файловой переменной не вызвана процедура Assign!!File variable was not assigned using Assign'; FILE_NOT_OPENED = 'Файл не открыт!!File is not open'; FILE_NOT_OPENED_FOR_READING = 'Файл не открыт на чтение!!File is not open for reading'; FILE_NOT_OPENED_FOR_WRITING = 'Файл не открыт на запись!!File is not open for writing'; READ_LEXEM_AFTER_END_OF_TEXT_FILE = 'Попытка считывания за концом текстового файла!!Attempt to read beyond end of text file'; READ_LEXEM_AFTER_END_OF_INPUT_STREAM = 'Попытка считывания за концом потока ввода!!Attempt to read beyond end of input stream'; RANGE_ERROR_MESSAGE = 'Выход за пределы допустимого диапазона!!Out of range'; EOF_FOR_TEXT_WRITEOPENED = 'Функция Eof не может быть вызвана для текстового файла, открытого на запись!!Eof function cannot be called on a text file opened for writing'; EOLN_FOR_TEXT_WRITEOPENED = 'Функция Eoln не может быть вызвана для текстового файла, открытого на запись!!Eoln function cannot be called on a text file opened for writing'; SEEKEOF_FOR_TEXT_WRITEOPENED = 'Функция SeekEof не может быть вызвана для текстового файла, открытого на запись!!SeekEof function cannot be called on a text file opened for writing'; SEEKEOLN_FOR_TEXT_WRITEOPENED = 'Функция SeekEoln не может быть вызвана для текстового файла, открытого на запись!!SeekEoln function cannot be called on a text file opened for writing'; BAD_TYPE_IN_RUNTIMESIZEOF = 'Типизированный файл не может содержать ссылочный тип или тип со ссылочными полями!!Typed file cannot contain a reference type or a type with reference fields'; PARAMETER_MUST_BE_GREATER_EQUAL_0 = 'Параметр должен быть >= 0!!Parameter must be >= 0'; PARAMETER_MUST_BE_GREATER_0 = 'Параметр должен быть больше 0!!Parameter must be > 0'; PARAMETER_MUST_BE_GREATER_1 = 'Параметр должен быть больше 1!!Parameter must be > 1'; PARAMETER_STEP_MUST_BE_NOT_EQUAL_0 = 'Параметр step не может быть равен 0!!Step parameter must not be equal to 0'; PARAMETER_STEP_MUST_BE_GREATER_0 = 'Параметр step должен быть > 0!!Step parameter must be greater than 0'; PARAMETER_FROM_OUT_OF_RANGE = 'Параметр from за пределами диапазона!!From parameter is out of range'; PARAMETER_TO_OUT_OF_RANGE = 'Параметр to за пределами диапазона!!To parameter is out of range'; ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE = 'Размер одномерного массива не согласован с размером двумерного массива!!The length of the 1D array must match the size of the 2D array'; INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT = 'Количество инициализирующих элементов не совпадает с количеством элементов матрицы!!The number of initializer elements must equal the number of elements in the matrix'; TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY = 'При открытии типизированного файла можно указывать только однобайтную кодировку!!Typed files can only be opened with single-byte encodings'; BAD_ROW_INDEX = 'Один из элементов массива RowIndex выходит за пределы индексов строк двумерного массива!!An element in the RowIndex array is out of range for the matrix row indices'; BAD_COL_INDEX = 'Один из элементов массива ColIndex выходит за пределы индексов столбцов двумерного массива!!An element in the ColIndex array is out of range for the matrix column indices'; BAD_ROW_INDEX_FROM = 'FromRow выходит за пределы индексов строк двумерного массива!!FromRow is out of range for the matrix row indices'; BAD_ROW_INDEX_TO = 'ToRow выходит за пределы индексов строк двумерного массива!!ToRow is out of range for the matrix row indices'; BAD_COL_INDEX_FROM = 'FromCol выходит за пределы индексов строк двумерного массива!!FromCol is out of range for the matrix column indices'; BAD_COL_INDEX_TO = 'ToCol выходит за пределы индексов строк двумерного массива!!ToCol is out of range for the matrix column indices'; SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL = 'Размеры среза и присваиваемого выражения должны быть равны!!Slice size must match the size of the assigned expression'; MATR_DIMENSIONS_MUST_BE_EQUAL = 'Размеры матриц должны совпадать!!Matrix dimensions must be equal'; COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1 = 'Количество параметров функции Max должно быть > 1!!Max function must have more than one parameter'; COUNT_PARAMS_MINFUN_MUSTBE_GREATER1 = 'Количество параметров функции Min должно быть > 1!!Min function must have more than one parameter'; Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a valid format'; Overflow_Int32 = 'Целочисленное переполнение!!Integer overflow'; FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!The step of a for loop cannot be 0'; SEQUENCE_CANNOT_BE_EMPTY = 'Последовательность не может быть пустой!!Sequence cannot be empty'; ARRAY_CANNOT_BE_EMPTY = 'Массив не может быть пустым!!Array cannot be empty'; MIN_CANNOT_BE_GREATER_THAN_MAX = 'CLamp: min не может быть больше чем max!!CLamp: min cannot be greater than max'; // ----------------------------------------------------- // WINAPI // ----------------------------------------------------- function WINAPI_AllocConsole: longword; external 'kernel32.dll' name 'AllocConsole'; var console_alloc: boolean := false; type BinaryFormatter = System.Runtime.Serialization.Formatters.Binary.BinaryFormatter; // ----------------------------------------------------- // Internal functions // ----------------------------------------------------- function GetCurrentLocale: string; begin var locale: object; if __CONFIG__.TryGetValue('locale', locale) then Result := locale as string else Result := 'ru'; end; function GetTranslation(message: string): string; begin var cur_locale := GetCurrentLocale(); var arr := message.Split(new string[1]('!!'), StringSplitOptions.None); if (cur_locale = 'en') and (arr.Length > 1) then Result := arr[1] else Result := arr[0] end; constructor ZeroStepException.Create; begin inherited Create(GetTranslation(FOR_STEP_CANNOT_BE_EQUAL0)) end; function IsWDE: boolean; begin Result := AppDomain.CurrentDomain.GetData('_RedirectIO_SpecialArgs') <> nil; end; [System.Security.SecuritySafeCriticalAttribute] procedure AllocConsole; begin if not IsConsoleApplication and (System.Environment.OSVersion.Platform <> PlatformID.Unix) and (AppDomain.CurrentDomain.GetData('_RedirectIO_SpecialArgs') = nil) then WINAPI_AllocConsole; console_alloc := true; end; function GetNullBasedArray(arr: object): System.Array; var fi: System.Reflection.FieldInfo; begin fi := arr.GetType.GetField(InternalNullBasedArrayName); if fi <> nil then Result := System.Array(fi.GetValue(arr)) else Result := nil; end; function FormatFloatNumber(s: string): string; begin Result := s.Replace(',', '.'); end; procedure ClipSet(var s: TypedSet; low, high: object); begin s.low_bound := low; s.upper_bound := high; s.Clip; end; function ClipSetFunc(s: TypedSet; low, high: object): TypedSet; begin s.low_bound := low; s.upper_bound := high; s.Clip(); Result := s; end; function ClipShortStringInSet(s: TypedSet; len: integer): TypedSet; begin s.len := len; s.Clip; Result := s; end; procedure ClipShortStringInSetProcedure(var s: TypedSet; len: integer); begin s.len := len; s.Clip; end; procedure AssignSet(var left: TypedSet; right: TypedSet); begin left := right.CloneSet(); end; procedure AssignSetWithBounds(var left: TypedSet; right: TypedSet; low, high: object); begin left := right.CloneSet(); left.low_bound := low; right.upper_bound := high; end; procedure TypedSetInit(var st: TypedSet); begin if st = nil then st := new TypedSet; end; procedure TypedSetInitWithBounds(var st: TypedSet; low, high: object); begin if st = nil then st := new TypedSet(low, high); end; procedure TypedSetInitWithShortString(var st: TypedSet; len: integer); begin if st = nil then st := new TypedSet(len); end; // ----------------------------------------------------- // Diapason // ----------------------------------------------------- constructor Diapason.Create(_low, _high: integer); begin low := _low;high := _high; end; constructor Diapason.Create(_low, _high: object); begin clow := _low;chigh := _high; end; // ----------------------------------------------------- // TypedSet // ----------------------------------------------------- ///-- constructor TypedSet.Create; begin ht := new Hashtable({new TypedSetComparer()}); end; ///-- constructor TypedSet.Create(len: integer); begin ht := new Hashtable({new TypedSetComparer()}); Self.len := len; end; ///-- constructor TypedSet.Create(low_bound, upper_bound: object); begin ht := new Hashtable({new TypedSetComparer()}); Self.low_bound := low_bound; Self.upper_bound := upper_bound; end; ///-- constructor TypedSet.Create(initValue: TypedSet); begin ht := new Hashtable({new TypedSetComparer()}); Self.AssignSetFrom(initValue); Self.len := initValue.len; end; ///-- constructor TypedSet.Create(low_bound, upper_bound: object; initValue: TypedSet); begin ht := new Hashtable({new TypedSetComparer()}); Self.low_bound := low_bound; Self.upper_bound := upper_bound; Self.AssignSetFrom(initValue); end; ///-- constructor TypedSet.Create(vals: array of byte); var i: integer; begin ht := new Hashtable({new TypedSetComparer()}); i := 0; while i < 256 div 8 do begin if vals[i] and 128 = 128 then ht.Add(i * 8, i * 8); if vals[i] and 64 = 64 then ht.Add(i * 8 + 1, i * 8 + 1); if vals[i] and 32 = 32 then ht.Add(i * 8 + 2, i * 8 + 2); if vals[i] and 16 = 16 then ht.Add(i * 8 + 3, i * 8 + 3); if vals[i] and 8 = 8 then ht.Add(i * 8 + 4, i * 8 + 4); if vals[i] and 4 = 4 then ht.Add(i * 8 + 5, i * 8 + 5); if vals[i] and 2 = 2 then ht.Add(i * 8 + 6, i * 8 + 6); if vals[i] and 1 = 1 then ht.Add(i * 8 + 7, i * 8 + 7); i := i + 1; end; end; ///-- procedure TypedSet.CreateIfNeed; begin if ht = nil then ht := new Hashtable({new TypedSetComparer()}); end; [System.Diagnostics.DebuggerStepThrough] function TypedSet.CloneSet: TypedSet; begin Result := new TypedSet(); Result.ht := ht.Clone() as Hashtable; //Result.copy_ht := ht; Result.low_bound := low_bound; Result.upper_bound := upper_bound; end; ///-- function TypedSet.GetBytes: array of byte; var ba: System.Collections.BitArray; i: integer; begin ba := new BitArray(256); Result := nil; foreach o: object in ht.Keys do begin try i := Convert.ToInt32(o); if (i < 0) and (i >= -128) and (i <= 127) then ba[i + 128] := true else if (i >= 0) and (i <= 255) then ba[i] := true; except on e: System.Exception do begin Result := nil; //Exit; end; end; end; SetLength(Result, 256 div 8); i := 0; while i < 256 div 8 do begin Result[i] := Convert.ToByte(ba[i * 8 + 7]) or (Convert.ToByte(ba[i * 8 + 6]) shl 1) or (Convert.ToByte(ba[i * 8 + 5]) shl 2) or (Convert.ToByte(ba[i * 8 + 4]) shl 3) or (Convert.ToByte(ba[i * 8 + 3]) shl 4) or (Convert.ToByte(ba[i * 8 + 2]) shl 5) or (Convert.ToByte(ba[i * 8 + 1]) shl 6) or (Convert.ToByte(ba[i * 8]) shl 7); i := i + 1; end; end; ///-- function TypedSet.UnionSet(s: TypedSet): TypedSet; begin Result := Union(Self, s); end; ///-- function TypedSet.SubtractSet(s: TypedSet): TypedSet; begin Result := Subtract(Self, s); end; ///-- function TypedSet.IntersectSet(s: TypedSet): TypedSet; begin Result := Intersect(Self, s); end; ///-- function TypedSet.IsInDiapason(elem: object): boolean; begin if (low_bound <> nil) and (upper_bound <> nil) and (elem is System.IComparable) then begin case System.Type.GetTypeCode(elem.GetType) of TypeCode.Char: begin if ((elem as System.IComparable).CompareTo(Convert.ToChar(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToChar(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.Int32: begin if not (elem is integer) then elem := Convert.ToInt32(elem); if ((elem as System.IComparable).CompareTo(Convert.ToInt32(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToInt32(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.Byte: begin if ((elem as System.IComparable).CompareTo(Convert.ToByte(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToByte(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.SByte: begin if ((elem as System.IComparable).CompareTo(Convert.ToSByte(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToSByte(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.Int16: begin if ((elem as System.IComparable).CompareTo(Convert.ToInt16(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToInt16(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.UInt16: begin if ((elem as System.IComparable).CompareTo(Convert.ToUint16(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToUInt16(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.UInt32: begin if ((elem as System.IComparable).CompareTo(Convert.ToUInt32(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToUInt32(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.Int64: begin if ((elem as System.IComparable).CompareTo(Convert.ToInt64(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToInt64(upper_bound)) <= 0) then Result := true else Result := false end; TypeCode.UInt64: begin if ((elem as System.IComparable).CompareTo(Convert.ToUInt64(low_bound)) >= 0) and ((elem as System.IComparable).CompareTo(Convert.ToUInt64(upper_bound)) <= 0) then Result := true else Result := false end; else if elem.GetType().IsEnum then begin if ((Convert.ToInt32(elem)).CompareTo(Convert.ToInt32(low_bound)) >= 0) and ((Convert.ToInt32(elem)).CompareTo(Convert.ToInt32(upper_bound)) <= 0) then Result := true else Result := false end else Result := true; end// case end // then else Result := true; end; function convert_elem(obj: object): object;// для TypedSet begin var t := obj.GetType; if t.IsEnum then begin Result := obj; exit; end; case System.Type.GetTypeCode(t) of TypeCode.Byte, TypeCode.SByte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32: Result := Convert.ToInt32(obj); TypeCode.UInt32: begin var tmp: longword := longword(obj); if tmp <= integer.MaxValue then Result := integer(tmp) else Result := Convert.ToInt64(obj); end; TypeCode.Int64: begin var tmp: int64 := int64(obj); if tmp <= integer.MaxValue then Result := integer(tmp) else Result := obj; end; TypeCode.UInt64: begin var tmp: uint64 := uint64(obj); if tmp <= integer.MaxValue then Result := integer(tmp) else if tmp <= int64.MaxValue then Result := int64(tmp) else Result := obj; end else Result := obj; end; end; ///-- function TypedSet.Contains(elem: object): boolean; begin if elem.GetType().IsEnum then begin Result := ht[elem] <> nil end else begin elem := convert_elem(elem); Result := ht.ContainsKey(elem);// <> nil; if not Result and (elem is char) then Result := ht.ContainsKey(Convert.ToString(elem)); end; end; ///-- procedure TypedSet.Clip; begin if Self.len > 0 then begin Clip(Self.len); exit; end; var tmp_ht := new Hashtable(); foreach el: object in ht.Keys do begin if IsInDiapason(el) then begin if (Self.low_bound <> nil) then begin var tmp := convert_elem(el); tmp_ht.Add(tmp, tmp) end else tmp_ht.Add(el, el); end; end; ht := tmp_ht; end; ///-- procedure TypedSet.Clip(len: integer); begin var tmp_ht := new Hashtable(); foreach el: object in ht.Keys do begin var str_el := Convert.ToString(el); if str_el.Length > len then begin var s := str_el.Substring(0, len); tmp_ht.Add(s, s); end else tmp_ht.Add(str_el, str_el); end; ht := tmp_ht; end; procedure TypedSet.IncludeElement(elem: object); var diap: Diapason; begin if elem = nil then exit; elem := convert_elem(elem); if not IsInDiapason(elem) then Exit; if elem.GetType().IsEnum then begin ht[elem] := elem; //if copy_ht <> nil then // copy_ht[elem] := elem; end else if not (elem is Diapason) then begin ht[elem] := elem; //if copy_ht <> nil then // copy_ht[elem] := elem; end else begin diap := Diapason(elem); if diap.clow = nil then begin for var i := diap.low to diap.high do begin ht[i] := i; //if copy_ht <> nil then // copy_ht[i] := i; end end else begin if diap.clow is char then begin for var c := char(diap.clow) to char(diap.chigh) do begin ht[c] := c; //if copy_ht <> nil then // copy_ht[c] := c; end end else if diap.clow is boolean then begin for var b := boolean(diap.clow) to boolean(diap.chigh) do ht[b] := b; end else if diap.clow.GetType().IsEnum then begin for var i := integer(diap.clow) to integer(diap.chigh) do begin var obj := Enum.ToObject(diap.clow.GetType(), i); ht[obj] := obj; //if copy_ht <> nil then // copy_ht[obj] := obj; end; end; end; end; end; procedure TypedSet.ExcludeElement(elem: object); begin if elem.GetType().IsEnum then begin ht.Remove(elem); end else begin elem := convert_elem(elem); ht.Remove(elem); end end; ///-- procedure TypedSet.Init(params elems: array of object); begin for var i := 0 to elems.Length - 1 do ht[elems[i]] := elems[i]; end; [System.Diagnostics.DebuggerStepThrough] procedure TypedSet.AssignSetFrom(s: TypedSet); begin ht := s.ht.Clone() as Hashtable; Clip; end; ///-- function TypedSet.GetEnumerator: System.Collections.IEnumerator; begin Result := ht.Keys.GetEnumerator; end; function FormatStr(obj: object): string; begin if (obj.GetType = typeof(char)) or (obj.GetType = typeof(string)) then Result := '''' + string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, '{0}', new object[](obj)) + '''' else Result := string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, '{0}', new object[](obj)) end; class function TypedSet.InitBy(s: sequence of T): TypedSet; begin var ts := new TypedSet(); foreach key: T in s do begin ts.ht[key] := key; end; Result := ts; end; ///-- class function TypedSet.operator implicit(s: TypedSet): HashSet; begin var hs := new HashSet(); foreach var key in s.ht.Keys do begin hs.Add(T(key)); end; Result := hs; end; ///-- class function TypedSet.operator implicit(s: HashSet): TypedSet; begin var ts := new TypedSet(); foreach key: T in s.ToArray() do begin ts.ht[key] := key; end; Result := ts; end; ///-- {class function TypedSet.operator implicit(s: array of T): TypedSet; begin var ts := new TypedSet(); foreach key: T in s do begin ts.ht[key] := key; end; Result := ts; end;} ///-- function TypedSet.ToString: string; var i: System.Collections.IEnumerator; lst: ArrayList; begin i := GetEnumerator; lst := new ArrayList(); var t: &Type; var added := false; if i.MoveNext then if not (i.Current is System.IComparable) then begin result := '' + FormatStr(i.Current) + ''; added := true; end else begin lst.Add(i.Current); t := i.Current.GetType; end; while i.MoveNext do if not (i.Current is System.IComparable) then begin result := (added ? result + ',' : '') + FormatStr(i.Current); added := true; end else begin if (t <> nil) and (t <> i.Current.GetType) then begin result := (added ? result + ',' : '') + FormatStr(i.Current); added := true; end else begin t := i.Current.GetType; lst.Add(i.Current); end; end; if lst.Count > 0 then begin lst.Sort; var ind := 1; if not added then result := '' + FormatStr(lst[0]) + '' else ind := 0; for j: integer := ind to lst.Count - 1 do begin result := result + ',' + FormatStr(lst[j]); end; end; result := '[' + result + ']'; end; {class function TypedSet.operator implicit(hset: HashSet): TypedSet; begin Result := new TypedSet(); foreach var x in hset do Result.ht[x] := x; end;} ///-- function TypedSet.CompareEquals(s: TypedSet): boolean; begin Result := CompareSetEquals(Self, s); end; ///-- function TypedSet.CompareInEquals(s: TypedSet): boolean; begin Result := CompareSetInEquals(Self, s); end; ///-- function TypedSet.CompareLess(s: TypedSet): boolean; begin Result := CompareSetLess(Self, s); end; ///-- function TypedSet.CompareLessEqual(s: TypedSet): boolean; begin Result := CompareSetLessEqual(Self, s); end; ///-- function TypedSet.CompareGreater(s: TypedSet): boolean; begin Result := CompareSetGreater(Self, s); end; ///-- function TypedSet.CompareGreaterEqual(s: TypedSet): boolean; begin Result := CompareSetGreaterEqual(Self, s); end; procedure TypedSet.Print(delim: string); begin foreach var x in ht.Keys do Write(x,delim) end; procedure TypedSet.Println(delim: string); begin var fst := True; foreach var x in ht.Keys do begin if fst then begin fst := False; Write(x); end else Write(delim,x); end; Writeln; end; // ----------------------------------------------------- // Typed Set functions // ----------------------------------------------------- [System.Diagnostics.DebuggerStepThrough] function CreateSet: TypedSet; begin Result := new TypedSet(); end; [System.Diagnostics.DebuggerStepThrough] function CreateBoundedSet(low, high: object): TypedSet; begin Result := new TypedSet(low, high); end; [System.Diagnostics.DebuggerStepThrough] function CreateDiapason(low, high: integer): Diapason; begin Result.low := low; Result.high := high; end; //[System.Diagnostics.DebuggerStepThrough] function CreateObjDiapason(low, high: object): Diapason; begin Result.clow := low; Result.chigh := high; end; [System.Diagnostics.DebuggerStepThrough] function CreateSet(params elems: array of object): TypedSet; begin var chars := false; var strings := false; var others := false; foreach var x in elems do begin if (x is char) or (x is Diapason) and (Diapason(x).clow is char) then chars := true else if x is string then strings := true else begin others := true; break end; end; Result := new TypedSet(); if chars and strings and not others then foreach var x in elems do if x is char then Result.IncludeElement(x.ToString) else if (x is Diapason) and (Diapason(x).clow is char) then begin var c1 := char(Diapason(x).clow); var c2 := char(Diapason(x).chigh); for var cc := c1 to c2 do Result.IncludeElement(cc.ToString) end else Result.IncludeElement(x) else foreach var x in elems do Result.IncludeElement(x); end; [System.Diagnostics.DebuggerStepThrough] function Subtract(s1, s2: TypedSet): TypedSet; begin Result := s1.CloneSet; var en := s2.ht.GetEnumerator(); while en.MoveNext do begin if s1.Contains(en.Key) then Result.ht.Remove(en.Key); end; end; [System.Diagnostics.DebuggerStepThrough] procedure Include(var s: TypedSet; el: object); begin s.IncludeElement(el); end; [System.Diagnostics.DebuggerStepThrough] procedure Exclude(var s: TypedSet; el: object); begin s.ExcludeElement(el); end; procedure Include(var s: NewSet; el: T) := s.Add(el); procedure Exclude(var s: NewSet; el: T) := s.Remove(el); procedure Include(var s: NewSet; el: byte) := s.Add(el); procedure Exclude(var s: NewSet; el: byte) := s.Remove(el); procedure Include(var s: NewSet; el: word) := s.Add(el); procedure Exclude(var s: NewSet; el: word) := s.Remove(el); procedure Include(var s: NewSet; el: integer) := s.Add(el); procedure Exclude(var s: NewSet; el: integer) := s.Remove(el); procedure Include(var s: NewSet; el: longword) := s.Add(el); procedure Exclude(var s: NewSet; el: longword) := s.Remove(el); procedure Include(var s: NewSet; el: shortint) := s.Add(el); procedure Exclude(var s: NewSet; el: shortint) := s.Remove(el); procedure Include(var s: NewSet; el: smallint) := s.Add(el); procedure Exclude(var s: NewSet; el: smallint) := s.Remove(el); procedure Include(var s: NewSet; el: int64) := s.Add(el); procedure Exclude(var s: NewSet; el: int64) := s.Remove(el); procedure Include(var s: NewSet; el: uint64) := s.Add(el); procedure Exclude(var s: NewSet; el: uint64) := s.Remove(el); [System.Diagnostics.DebuggerStepThrough] function Union(s1, s2: TypedSet): TypedSet; begin Result := s1.CloneSet; var en := s2.ht.GetEnumerator(); while en.MoveNext do Result.ht[en.Key] := en.Key; end; [System.Diagnostics.DebuggerStepThrough] function Intersect(s1, s2: TypedSet): TypedSet; var en: System.Collections.IEnumerator; begin Result := new TypedSet(); en := s1.ht.GetEnumerator(); while en.MoveNext do if s2.Contains((en as IDictionaryEnumerator).Key) then Result.ht[(en as IDictionaryEnumerator).Key] := (en as IDictionaryEnumerator).Key; end; [System.Diagnostics.DebuggerStepThrough] function InSet(obj: object; s: TypedSet): boolean; begin {if obj.GetType().IsEnum then Result := s.ht[obj] <> nil else} Result := (obj <> nil) and s.Contains(obj); {Result := (obj <> nil) and (s.ht[obj] <> nil); if not Result and (obj is TypedSet) then Result := s.Contains(obj as TypedSet);} //if Result = true then // Result := s.IsInDiapason(obj); end; [System.Diagnostics.DebuggerStepThrough] function CompareSetEquals(s1, s2: TypedSet): boolean; var en: System.Collections.IEnumerator; equals: boolean := true; begin if s1.ht.Count <> s2.ht.Count then begin Result := false; Exit; end; en := s1.ht.GetEnumerator(); while en.MoveNext do begin var is_in_s1 := s1.Contains((en as IDictionaryEnumerator).Key); var is_in_s2 := s2.Contains((en as IDictionaryEnumerator).Key); if is_in_s1 and not is_in_s2 then begin equals := false; break; end else if not is_in_s1 and is_in_s2 then begin equals := false; break; end end; if equals <> false then begin en := s2.ht.GetEnumerator(); en.Reset(); while en.MoveNext do begin var is_in_s1 := s1.Contains((en as IDictionaryEnumerator).Key); var is_in_s2 := s2.Contains((en as IDictionaryEnumerator).Key); if is_in_s2 and not is_in_s1 then begin equals := false; break; end else if not is_in_s2 and is_in_s1 then begin equals := false; break; end end; end; Result := equals; end; [System.Diagnostics.DebuggerStepThrough] function CompareSetInEquals(s1, s2: TypedSet): boolean; begin Result := not CompareSetEquals(s1, s2); end; [System.Diagnostics.DebuggerStepThrough] function CompareSetLess(s1, s2: TypedSet): boolean; var en: System.Collections.IEnumerator; less: boolean := true; begin en := s1.ht.GetEnumerator(); en.Reset(); while en.MoveNext do begin if not s2.Contains((en as IDictionaryEnumerator).Key) then begin less := false; break; end; end; if less <> false then begin en := s2.ht.GetEnumerator(); en.Reset(); var b: boolean := false; while en.MoveNext do begin if not s1.Contains((en as IDictionaryEnumerator).Key) then begin b := true; break; end; end; less := b; end; Result := less; end; [System.Diagnostics.DebuggerStepThrough] function CompareSetGreaterEqual(s1, s2: TypedSet): boolean; var en: System.Collections.IEnumerator; greater: boolean := true; begin en := s2.ht.GetEnumerator(); en.Reset(); while en.MoveNext do begin if not s1.Contains((en as IDictionaryEnumerator).Key) then begin greater := false; break; end; end; Result := greater; end; [System.Diagnostics.DebuggerStepThrough] function CompareSetLessEqual(s1, s2: TypedSet): boolean; var en: System.Collections.IEnumerator; less: boolean := true; begin en := s1.ht.GetEnumerator(); en.Reset(); while en.MoveNext do begin if not s2.Contains((en as IDictionaryEnumerator).Key) then begin less := false; break; end; end; Result := less; end; [System.Diagnostics.DebuggerStepThrough] function CompareSetGreater(s1, s2: TypedSet): boolean; var greater: boolean := true; en: System.Collections.IEnumerator; begin en := s2.ht.GetEnumerator(); en.Reset(); while en.MoveNext do begin if not s1.Contains((en as IDictionaryEnumerator).Key) then begin greater := false; break; end; end; if greater <> false then begin en := s1.ht.GetEnumerator(); en.Reset(); var b: boolean := false; while en.MoveNext do begin if not s2.Contains((en as IDictionaryEnumerator).Key) then begin b := true; break; end; end; greater := b; end; Result := greater; end; // ----------------------------------------------------- // TypedFile // ----------------------------------------------------- constructor TypedFile.Create(ElementType: System.Type); begin Self.ElementType := ElementType; ElementSize := RuntimeSizeOf(ElementType); end; constructor TypedFile.Create(ElementType: System.Type; offs: integer; params offsets: array of integer); begin Self.ElementType := ElementType; ElementSize := RuntimeSizeOf(ElementType); Self.offsets := offsets; if offs <> 0 then begin ElementSize := ElementSize + offs{*2}; offset := offs{*2}; end; end; function TypedFile.ToString := Format('file of {0}', ElementType); // ----------------------------------------------------- // BinaryFile // ----------------------------------------------------- function BinaryFile.ToString: string := 'file'; // ----------------------------------------------------- // GCHandlersController // ----------------------------------------------------- constructor GCHandlersController.Create; begin Counters := new Hashtable; Handlers := new Hashtable; end; procedure GCHandlersController.Add(obj: Object); begin if obj <> nil then begin if Counters.Contains(obj) then Counters[obj] := integer(Counters[obj]) + 1 else begin Counters.Add(obj, 1); Handlers.Add(obj, GCHandle.Alloc(obj, GCHandleType.Pinned)); //var ptr := Marshal.AllocHGlobal(Marshal.SizeOf(obj)); //Marshal.StructureToPtr(obj, ptr, false); //Handlers.Add(obj, ptr); //GC.KeepAlive(obj); //var ptr:=IntPtr(pointer(@obj)); //Handlers.Add(obj,new IntPtr(integer(ptr) or 1)); end; end; end; procedure GCHandlersController.Remove(obj: Object); begin if obj <> nil then begin if Counters.Contains(obj) then begin var Count := integer(Counters[obj]); if Count > 1 then Counters[obj] := Count - 1 else begin Counters.Remove(obj); GCHandle(Handlers[obj]).Free; Handlers.Remove(obj); end; end else raise new SystemException('PABCSystem.GCHandleForPointersController not contains object ' + obj.ToString); end; end; function GCHandlersController.GetCounter(obj: Object): integer; begin result := 0; if Counters.Contains(obj) then result := integer(Counters[obj]); end; function GCHandlersController.GetEnumerator: System.Collections.IEnumerator; begin result := Counters.Keys.GetEnumerator; end; function IntRange.GetEnumerator: IEnumerator := Range(l,h).GetEnumerator; function IntRange.Step(n: integer): sequence of integer := Range(l,h,n); function IntRange.Reverse: sequence of integer := Range(h,l, -1); function CharRange.GetEnumerator: IEnumerator := Range(l,h).GetEnumerator; function CharRange.Step(n: integer): sequence of char := Range(l,h,n); function CharRange.Reverse: sequence of char := Range(h,l, -1); //------------------------------------------------------------------------------ // Операции для string и char //------------------------------------------------------------------------------ ///-- procedure string.operator+=(var left: string; right: string); begin left := left + right; end; ///-- function string.operator<(left, right: string) := string.CompareOrdinal(left, right) < 0; ///-- function string.operator<=(left, right: string) := string.CompareOrdinal(left, right) <= 0; ///-- function string.operator>(left, right: string) := string.CompareOrdinal(left, right) > 0; ///-- function string.operator>=(left, right: string) := string.CompareOrdinal(left, right) >= 0; ///-- function string.operator*(str: string; n: integer): string; begin var sb := new StringBuilder; loop n do sb.Append(str); Result := sb.ToString; end; ///-- function string.operator*(n: integer; str: string): string; begin var sb := new StringBuilder; loop n do sb.Append(str); Result := sb.ToString; end; ///-- function char.operator*(c: char; n: integer): string; begin if n <= 0 then begin Result := ''; exit; end; var sb := new StringBuilder(n, n); loop n do sb.Append(c); Result := sb.ToString; end; ///-- function char.operator*(n: integer; c: char): string; begin if n <= 0 then begin Result := ''; exit; end; var sb := new StringBuilder(n, n); loop n do sb.Append(c); Result := sb.ToString; end; // Добавляет к строке str строковое представление числа n ///-- function string.operator+(str: string; n: integer) := str + n.ToString; // Добавляет к строке str строковое представление числа n ///-- function string.operator+(str: string; n: uint64) := str + n.ToString; // Добавляет к строке str строковое представление числа n ///-- function string.operator+(str: string; n: int64) := str + n.ToString; // Добавляет к строке str строковое представление числа n ///-- function string.operator+(str: string; n: longword) := str + n.ToString; // Добавляет к строке str строковое представление числа n ///-- function string.operator+(n: integer; str: string) := n.ToString + str; // Добавляет к строке str строковое представление числа r ///-- function string.operator+(str: string; r: real) := str + r.ToString(nfi); // Добавляет к строке str строковое представление числа r ///-- function string.operator+(r: real; str: string) := r.ToString(nfi) + str; ///-- procedure string.operator+=(var left: string; right: integer); begin left := left + right.ToString; end; procedure string.operator+=(var left: string; right: real); begin left := left + right.ToString(nfi); end; procedure string.operator*=(var left: string; n: integer); begin var sb := new StringBuilder; loop n do sb.Append(left); left := sb.ToString; end; function string.operator in(substr: string; str: string) := str.Contains(substr); procedure operator+=(var left: StringBuilder; right: string); extensionmethod := left.Append(right); function operator implicit(s: string): StringBuilder; extensionmethod := new StringBuilder(s); //------------------------------------------------------------------------------ // ObjectToString //------------------------------------------------------------------------------ procedure TypeToTypeNameHelper(t: System.Type; res: TextWriter); forward; type ObjectToStringUtils = static class public static procedure MethodToString(mi: System.Reflection.MethodInfo; write_sub_names: boolean; res: TextWriter); const lambda_name='lambda'; const sugar_name_begin='<>'; const par_separator = ', '; begin var rt := mi.ReturnType; if rt=typeof(Void) then rt := nil; res.Write( if rt=nil then 'procedure' else 'function' ); if write_sub_names then begin res.Write(' '); var name := mi.Name; if name.StartsWith(sugar_name_begin) then begin if name.IndexOf(lambda_name, sugar_name_begin.Length, lambda_name.Length)=-1 then res.Write( name.Substring(sugar_name_begin.Length) ) else res.Write( lambda_name ); end else res.Write( name ); end; var pars := mi.GetParameters; if pars.Length<>0 then begin res.Write('('); for var i := 0 to pars.Length-1 do begin var par := pars[i]; if i<>0 then res.Write( par_separator ); if write_sub_names then begin var name := par.Name; if name.StartsWith(sugar_name_begin) then res.Write( name.SubString(sugar_name_begin.Length) ) else res.Write( name ); res.Write(': '); end; TypeToTypeNameHelper(par.ParameterType, res); end; res.Write(')'); end; if rt<>nil then begin res.Write(': '); TypeToTypeNameHelper(rt, res); end; end; private static empty_obj_arr := new object[0]; public static procedure ContentsToString(o: Object; prev: Stack; res: TextWriter); const val_sep = ','; begin res.Write('('); var any_vals := false; var inh_st := new Stack; begin var t := o.GetType; repeat inh_st.Push(t); t := t.BaseType; until t=nil; end; var bind_flags := System.Reflection.BindingFlags.Public or System.Reflection.BindingFlags.Instance or System.Reflection.BindingFlags.DeclaredOnly; foreach var t in inh_st do foreach var fi in t.GetFields(bind_flags) do begin if any_vals then res.Write( val_sep ) else any_vals := true; //res.Write( fi.Name ); //res.Write('='); Append(fi.GetValue(o), prev, res); end; foreach var t in inh_st do foreach var pi in t.GetProperties(bind_flags) do begin if pi.GetIndexParameters.Length<>0 then continue; var mi := pi.GetGetMethod; if mi=nil then continue; if any_vals then res.Write( val_sep ) else any_vals := true; //res.Write( pi.Name ); //res.Write('='); var val: object; try val := mi.Invoke(o, empty_obj_arr); except on e: System.Reflection.TargetInvocationException do val := e.InnerException.ToString; end; Append(val, prev, res); end; res.Write(')'); end; public static procedure Append(o: Object; prev: Stack; res: TextWriter); begin if prev.Contains(o) then begin res.Write( '(...)' ); exit; end; prev.Push(o); AppendImpl(o, prev, res); if prev.Pop<>o then raise new InvalidOperationException; end; public static procedure AppendImpl(o: Object; prev: Stack; res: TextWriter); const max_seq_len = 100; begin if o = nil then begin res.Write( 'nil' ); exit; end; var o_t := o.GetType; {$region Особые типы} if o is System.Reflection.Pointer then begin res.Write( PointerToString(System.Reflection.Pointer.Unbox(o)) ); exit; end; // Исправить это форматирование {if o is Complex then begin var c := Complex(o); res.Write('('); AppendImpl(c.Real, prev, res); res.Write(' + i*'); AppendImpl(c.Imaginary, prev, res); res.Write(')'); exit; end;} if o is Complex then begin var c := Complex(o); //res.Write('('); AppendImpl(c.Real, prev, res); if c.Imaginary >= 0 then res.Write('+'); AppendImpl(c.Imaginary, prev, res); res.Write('i'); exit; end; if o is Delegate then begin var d := Delegate(o); if d.Target<>nil then begin Append(d.Target, prev, res); res.Write(' => '); end; MethodToString(d.Method, true, res); exit; end; // Без пробела при выводе полей if o_t.IsGenericType and ((o_t.GetGenericTypeDefinition=typeof(KeyValuePair<,>)) or (o_t.FullName.StartsWith('System.Tuple`'))) then begin ContentsToString(o, prev, res); exit; end; begin var f := o.GetType.GetField('NullBasedArray'); if f<>nil then begin AppendImpl(f.GetValue(o), prev, res); exit; end; end; {$endregion Особые типы} {$region Переопределённый .ToString} if o is IFormattable then begin // Применение nfi к числам с плавающей точкой res.Write( IFormattable(o).ToString(nil, nfi) ); exit; end; begin var d: ()->string := o.ToString; var decl_t := d.Method.DeclaringType; if (decl_t<>typeof(object)) and (decl_t<>typeof(ValueType)) then begin res.Write( d() ); exit; end; end; {$endregion Переопределённый .ToString} {$region Array} if o is &Array then begin var a := &Array(o); if a.Length=0 then begin // Алгоритм ниже не расчитан на пустые массивы loop a.Rank do res.Write('['); loop a.Rank do res.Write(']'); exit; end; var inds := new integer[a.Rank]; var trim_inds := new Nullable[inds.Length]; var last_r := inds.Length-1; for var r := 0 to last_r do begin inds[r] := a.GetLowerBound(r); var trim_ind := inds[r]+max_seq_len-1; // Именно "<", не "<=", чтобы последний // элемент никогда не заменяло на ... if trim_inda.GetUpperBound(stack_pos); if not need_pop and (inds[stack_pos]=trim_inds[stack_pos]) then begin res.Write(',...'); need_pop := true; end; if need_pop then begin inds[stack_pos] := a.GetLowerBound(stack_pos); res.Write(']'); stack_pos -= 1; if stack_pos<0 then exit; end else begin res.Write(','); break; end; end; end; // Должен сработать exit выше raise new InvalidOperationException; end; {$endregion Array} {$region IEnumerable} if o is System.Collections.IEnumerable then begin var s := System.Collections.IEnumerable(o); var is_set := (o is TypedSet) or o.GetType.GetInterfaces.Contains(typeof(System.Collections.IDictionary)) or o.GetType.GetInterfaces.Any(intr->intr.IsGenericType and (intr.GetGenericTypeDefinition=typeof(System.Collections.Generic.ISet<>))); res.Write( if is_set then '{' else '[' ); var enmr := s.GetEnumerator; var len := 0; if enmr.MoveNext then while true do begin var enmr_curr := enmr.Current; var enmr_has_next := enmr.MoveNext; if len<>0 then res.Write(','); len += 1; if (len>max_seq_len) and enmr_has_next then begin res.Write( '...' ); enmr_has_next := false; end else Append(enmr_curr, prev, res); if not enmr_has_next then break; end; res.Write( if is_set then '}' else ']' ); exit; end; {$endregion IEnumerable} ContentsToString(o, prev, res); end; end; function TryWriteFromTypeCode(t: System.Type; res: TextWriter): boolean; begin Result := not t.IsEnum; if not Result then exit; case &Type.GetTypeCode(t) of // int TypeCode.SByte: res.Write('shortint'); TypeCode.Byte: res.Write('byte'); TypeCode.Boolean: res.Write('boolean'); TypeCode.Int16: res.Write('smallint'); TypeCode.UInt16: res.Write('word'); TypeCode.Char: res.Write('char'); TypeCode.Int32: res.Write('integer'); TypeCode.UInt32: res.Write('longword'); TypeCode.Int64: res.Write('int64'); TypeCode.UInt64: res.Write('uint64'); TypeCode.DateTime:res.Write('DateTime'); // float TypeCode.Single: res.Write('single'); TypeCode.Double: res.Write('real'); TypeCode.Decimal: res.Write('decimal'); TypeCode.String: res.Write('string'); else Result := false; end; end; procedure TypeToTypeNameHelper(t: System.Type; res: TextWriter); begin if t=nil then begin res.Write( 'nil' ); exit; end; if TryWriteFromTypeCode(t, res) then exit; if t.IsArray then begin res.Write('array'); var rank := t.GetArrayRank; if rank>1 then begin res.Write('['); loop rank-1 do res.Write(','); res.Write(']'); end else if rank<1 then raise new NotImplementedException; res.Write(' of '); TypeToTypeNameHelper(t.GetElementType, res); exit; end; if t.IsGenericType and (t.GetGenericTypeDefinition = typeof(NewSet<>)) then begin res.Write('set of '); TypeToTypeNameHelper(t.GetGenericArguments.Single, res); exit; end; if t.GetInterfaces.Append(t).Contains(typeof(System.Collections.IEnumerable)) then begin var typed := t.GetInterfaces.Append(t).FirstOrDefault(intr->intr.IsGenericType and (intr.GetGenericTypeDefinition=typeof(IEnumerable<>))); if (t=typed) or (typed<>nil) and ( // Выводим как sequence только классы, созданные yield функцией // "clyield#" это yield класс паскаля t.Name.StartsWith('clyield#') or // А все yield классы C# являются вложенными и скрытыми t.IsNestedPrivate ) then begin res.Write('sequence of '); TypeToTypeNameHelper(typed.GetGenericArguments.Single, res); exit; end; end; var gen_args := t.GetGenericArguments; //TODO t.IsClass, чтобы ValueTuple пока что не ловило if t.GetInterfaces.Contains(typeof(System.Runtime.CompilerServices.ITuple)) and t.IsClass then begin res.Write('('); var any_gen_arg := false; foreach var arg in gen_args do begin if any_gen_arg then res.Write(', ') else any_gen_arg := true; TypeToTypeNameHelper(arg, res); end; res.Write(')'); exit; end; var name := t.Name; if t.IsSubclassOf(typeof(Delegate)) then begin var mi := t.GetMethod('Invoke'); // nil for System.MulticastDelegate if mi<>nil then begin ObjectToStringUtils.MethodToString(mi, false, res); exit; end; end; // "Lst(0).GetEnumerator.GetType.DeclaringType" возвращает List, а не List // При чём этот T.IsNested возвращает true, хотя это параметр а не вложенный тип if t.IsNested and not t.IsGenericParameter then begin var parent_def := t.DeclaringType; var parent := parent_def; if parent.IsGenericType then begin // Во вложенный тип копирует все типы шаблона из внешнего класса // class Parent { class Nested } // На практике вложенный тип будет Parent`1+Nested`1 // Но тут писать в res будем только var t_def_args := t.GetGenericTypeDefinition.GetGenericArguments; var parent_def_args := parent_def.GetGenericArguments; for var i := 0 to parent_def_args.Length-1 do if t_def_args[i].Name <> parent_def_args[i].Name then // Ожидается что всегда будет перед в примере выше raise new NotImplementedException; var parent_args := new System.Type[parent_def_args.Length]; &Array.ConstrainedCopy(gen_args,0, parent_args,0, parent_args.Length); parent := parent_def.MakeGenericType(parent_args); var own_args := new System.Type[gen_args.Length-parent_def_args.Length]; &Array.ConstrainedCopy(gen_args,parent_args.Length, own_args,0, own_args.Length); gen_args := own_args; end; TypeToTypeNameHelper(parent, res); res.Write('+'); end; if gen_args.Count<>0 then begin res.Write(name.Remove(name.LastIndexOf('`'))); res.Write('<'); var any_gen_arg := false; foreach var arg in gen_args do begin if any_gen_arg then res.Write(', ') else any_gen_arg := true; TypeToTypeNameHelper(arg, res); end; res.Write('>'); exit; end; if t.IsGenericParameter then res.Write('['); res.Write(name); if t.IsGenericParameter then res.Write(']'); end; procedure TypeToTypeNameHelper(t: System.Type; res: StringBuilder) := TypeToTypeNameHelper(t, new StringWriter(res)); procedure TypeNameHelper(obj: object; res: TextWriter); begin var t := obj?.GetType; // Зачем? TypeName(@a) не работает // Можно сделать TypeName волшебной функцией, вызывая // System.Reflection.Pointer.Box, но сейчас это не происходит // if t = typeof(System.Reflection.Pointer) then // begin // ... // exit; // end; var static_arr_field := t?.GetField('NullBasedArray'); if static_arr_field<>nil then begin TypeNameHelper(static_arr_field.GetValue(obj), res); exit; end; TypeToTypeNameHelper(t, res); end; procedure TypeNameHelper(obj: object; res: StringBuilder) := TypeNameHelper(obj, new StringWriter(res)); function TypeName(obj: object): string; begin var res := new StringBuilder; TypeNameHelper(obj, res); Result := res.ToString; end; function TypeToTypeName(t: System.Type): string; begin var res := new StringBuilder; TypeToTypeNameHelper(t, res); Result := res.ToString; end; procedure _ObjectToStringHelper(o: object; res: TextWriter) := ObjectToStringUtils.Append(o, new Stack, res); procedure _ObjectToStringHelper(o: object; res: StringBuilder) := _ObjectToStringHelper(o, new StringWriter(res)); function ObjectToString(obj: object): string; begin var res := new StringBuilder; _ObjectToStringHelper(obj, res); Result := res.ToString; end; function NumberFormat(DecimalSeparator: string; GroupSeparator: string): NumberFormatInfo; begin var nfi := new NumberFormatInfo; nfi.NumberDecimalSeparator := DecimalSeparator; nfi.NumberGroupSeparator := GroupSeparator; Result := nfi end; procedure SetDecimalSeparator(sep: string); begin nfi.NumberDecimalSeparator := sep; end; procedure SetNumberFormat(DecimalSeparator: string; GroupSeparator: string); begin nfi.NumberDecimalSeparator := DecimalSeparator; nfi.NumberGroupSeparator := GroupSeparator end; //------------------------------------------------------------------------------ // Операции для array of T //------------------------------------------------------------------------------ /// Объединяет два массива function operator+(a, b: array of T): array of T; extensionmethod; begin Result := new T[a.Length + b.Length]; a.CopyTo(Result, 0); b.CopyTo(Result, a.Length); end; ///-- function operator in(x: T; a: array of T): boolean; extensionmethod := a.Contains(x); // operator in для конкретных num in [1,2,3] - в PABCExtensions function operator*(a: array of T; n: integer): array of T; extensionmethod; begin if a.Length=1 then Result := ArrFill(n,a[0]) else begin Result := new T[a.Length * n]; for var i := 0 to n - 1 do a.CopyTo(Result, a.Length * i); end; end; function operator*(n: integer; a: array of T): array of T; extensionmethod := a * n; //------------------------------------------------------------------------------ // Операции для List //------------------------------------------------------------------------------ ///-- function operator+=(a, b: List): List; extensionmethod; begin a.AddRange(b); Result := a; end; ///-- function operator+(a, b: List): List; extensionmethod; begin Result := new List(a); Result.AddRange(b); end; ///-- function operator+=(a: List; x: T): List; extensionmethod; begin a.Add(x); Result := a; end; ///-- function List.operator in(x: T; Self: List): boolean; begin Result := Self.Contains(x); end; ///-- function operator*(a: List; n: integer): List; extensionmethod; begin Result := new List(); for var i := 1 to n do Result.AddRange(a); end; ///-- function operator*(n: integer; a: List): List; extensionmethod := a * n; //------------------------------------------------------------------------------ // Операции для Stack //------------------------------------------------------------------------------ ///-- function operator+=(s: Stack; x: T): Stack; extensionmethod; begin s.Push(x); Result := s; end; //------------------------------------------------------------------------------ // Операции для Queue //------------------------------------------------------------------------------ ///-- function operator+=(q: Queue; x: T): Queue; extensionmethod; begin q.Enqueue(x); Result := q; end; //------------------------------------------------------------------------------ // Операции для HashSet //------------------------------------------------------------------------------ ///-- function operator in(x: T; Self: HashSet): boolean; extensionmethod := Self.Contains(x); function operator+=(var Self: HashSet; x: T): HashSet; extensionmethod; begin Self.Add(x); Result := Self; end; function operator+=(var Self: HashSet; x: sequence of T): HashSet; extensionmethod; begin Self.UnionWith(x); Result := Self; end; function operator-=(var Self: HashSet; x: T): HashSet; extensionmethod; begin Self.Remove(x); Result := Self; end; function operator-=(var Self: HashSet; x: sequence of T): HashSet; extensionmethod; begin Self.ExceptWith(x); Result := Self; end; function InternalEqual(x,y: HashSet): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.SetEquals(y); end; function operator=(x,y: HashSet): boolean; extensionmethod := InternalEqual(x,y); function operator<>(x,y: HashSet); extensionmethod := not InternalEqual(x,y); function operator-(x, y: HashSet): HashSet; extensionmethod; begin var v := new HashSet(x); v.ExceptWith(y); Result := v; end; function operator+(x, y: HashSet): HashSet; extensionmethod; begin var v := new HashSet(x); v.UnionWith(y); Result := v; end; function operator+(x: HashSet; y: T): HashSet; extensionmethod; begin var v := new HashSet(x); v.Add(y); Result := v; end; function operator-(x: HashSet; y: T): HashSet; extensionmethod; begin var v := new HashSet(x); v.Remove(y); Result := v; end; function operator*(x,y: HashSet): HashSet; extensionmethod; begin var v := new HashSet(x); v.IntersectWith(y); Result := v; end; function operator< (x, y: HashSet); extensionmethod := x.IsProperSubsetOf(y); function operator<= (x, y: HashSet); extensionmethod := x.IsSubsetOf(y); function operator> (x, y: HashSet); extensionmethod := x.IsProperSupersetOf(y); function operator>= (x, y: HashSet); extensionmethod := x.IsSupersetOf(y); //------------------------------------------------------------------------------ // Операции для SortedSet //------------------------------------------------------------------------------ function operator in(x: T; Self: SortedSet): boolean; extensionmethod := Self.Contains(x); function operator+=(var Self: SortedSet; x: T): SortedSet; extensionmethod; begin Self.Add(x); Result := Self; end; function operator+=(var Self: SortedSet; x: sequence of T): SortedSet; extensionmethod; begin Self.UnionWith(x); Result := Self; end; function operator-=(var Self: SortedSet; x: T): SortedSet; extensionmethod; begin Self.Remove(x); Result := Self; end; function operator-=(var Self: SortedSet; x: sequence of T): SortedSet; extensionmethod; begin Self.ExceptWith(x); Result := Self; end; function InternalEqual(x,y: SortedSet): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.SetEquals(y); end; function operator=(x,y: SortedSet): boolean; extensionmethod := InternalEqual(x,y); function operator<>(x, y: SortedSet); extensionmethod := not InternalEqual(x,y); function operator-(x, y: SortedSet): SortedSet; extensionmethod; begin var v := new SortedSet(x); v.ExceptWith(y); Result := v; end; function operator+(x, y: SortedSet): SortedSet; extensionmethod; begin var v := new SortedSet(x); v.UnionWith(y); Result := v; end; function operator+(x: SortedSet; y: T): SortedSet; extensionmethod; begin var v := new SortedSet(x); v.Add(y); Result := v; end; function operator-(x: SortedSet; y: T): SortedSet; extensionmethod; begin var v := new SortedSet(x); v.Remove(y); Result := v; end; function operator*(x,y: SortedSet): SortedSet; extensionmethod; begin var v := new SortedSet(x); v.IntersectWith(y); Result := v; end; function operator< (x, y: SortedSet); extensionmethod := x.IsProperSubsetOf(y); function operator<= (x, y: SortedSet); extensionmethod := x.IsSubsetOf(y); function operator> (x, y: SortedSet); extensionmethod := x.IsProperSupersetOf(y); function operator>= (x, y: SortedSet): boolean; extensionmethod := x.IsSupersetOf(y); //------------------------------------------------------------------------------ // Операции для Dictionary, SortedDictionary, SortedList //------------------------------------------------------------------------------ function Dictionary.operator in(key: K; d: Dictionary): boolean; begin Result := d.ContainsKey(key); end; function SortedDictionary.operator in(key: K; d: SortedDictionary): boolean; begin Result := d.ContainsKey(key); end; function SortedList.operator in(key: K; d: SortedList): boolean; begin Result := d.ContainsKey(key); end; //------------------------------------------------------------------------------ // ** //------------------------------------------------------------------------------ function operator**(x: real; n: integer): real; extensionmethod := Power(x, n); function operator**(x: single; n: integer): real; extensionmethod := Power(x, n); function operator**(x, y: integer): real; extensionmethod := Power(real(x), y); function operator**(x, y: real): real; extensionmethod := Power(x, y); function operator**(x, y: Complex): Complex; extensionmethod := Power(x, y); function operator**(x: BigInteger; y: integer): BigInteger; extensionmethod := Power(x, y); //------------------------------------------------------------------------------ // Операции для BigInteger //------------------------------------------------------------------------------ function BigInteger.operator/(p: BigInteger; q: real) := real(p)/q; function BigInteger.operator/(q: real; p: BigInteger) := q/real(p); function BigInteger.operator>(p: BigInteger; q: integer) := p > BigInteger.Create(q); function BigInteger.operator>(p: integer; q: BigInteger) := BigInteger.Create(p) > q; function BigInteger.operator<(p: BigInteger; q: integer) := p < BigInteger.Create(q); function BigInteger.operator<(p: integer; q: BigInteger) := BigInteger.Create(p) < q; function BigInteger.operator>=(p: BigInteger; q: integer) := p >= BigInteger.Create(q); function BigInteger.operator>=(p: integer; q: BigInteger) := BigInteger.Create(p) >= q; function BigInteger.operator<=(p: BigInteger; q: integer) := p <= BigInteger.Create(q); function BigInteger.operator<=(p: integer; q: BigInteger) := BigInteger.Create(p) <= q; function BigInteger.operator=(p: BigInteger; q: integer) := p = BigInteger.Create(q); function BigInteger.operator=(p: integer; q: BigInteger) := BigInteger.Create(p) = q; function BigInteger.operator<>(p: BigInteger; q: integer) := p <> BigInteger.Create(q); function BigInteger.operator<>(p: integer; q: BigInteger) := BigInteger.Create(p) <> q; procedure BigInteger.operator+=(var p: BigInteger; q: BigInteger) := p := p + q; procedure BigInteger.operator*=(var p: BigInteger; q: BigInteger) := p := p * q; procedure BigInteger.operator-=(var p: BigInteger; q: BigInteger) := p := p - q; function BigInteger.operator div(p: BigInteger; q: integer) := BigInteger.Divide(p,q); function BigInteger.operator mod(p: BigInteger; q: integer) := BigInteger.Remainder(p,q); //function BigInteger.operator div(p,q: BigInteger) := BigInteger.Divide(p,q); //function BigInteger.operator mod(p,q: BigInteger) := BigInteger.Remainder(p,q); function BigInteger.operator-(p: BigInteger) := BigInteger.Negate(p); //------------------------------------------------------------------------------ // Операции для Decimal //------------------------------------------------------------------------------ function operator-(d: Decimal): Decimal; extensionmethod := Decimal.Negate(d); //------------------------------------------------------------------------------ // Операции для Complex //------------------------------------------------------------------------------ function operator-(Self: Complex): Complex; extensionmethod := Complex.Negate(Self); function operator implicit(c: (real,real)): Complex; extensionmethod := Cplx(c[0],c[1]); function operator implicit(c: (real,integer)): Complex; extensionmethod := Cplx(c[0],c[1]); function operator implicit(c: (integer,real)): Complex; extensionmethod := Cplx(c[0],c[1]); function operator implicit(c: (integer,integer)): Complex; extensionmethod := Cplx(c[0],c[1]); procedure operator+=(var c: Complex; x: Complex); extensionmethod := c := c + x; procedure operator*=(var c: Complex; x: Complex); extensionmethod := c := c * x; procedure operator-=(var c: Complex; x: Complex); extensionmethod := c := c - x; procedure operator/=(var c: Complex; x: Complex); extensionmethod := c := c / x; //------------------------------------------------------------------------------ // Операции для sequence of T //------------------------------------------------------------------------------ ///-- function operator+(a, b: sequence of T): sequence of T; extensionmethod; begin Result := a.Concat(b); end; ///-- function operator+(a: sequence of T; b: T): sequence of T; extensionmethod; begin Result := a.Concat(new T[1](b)); end; ///-- function operator+(b: T; a: sequence of T): sequence of T; extensionmethod; begin Result := new T[1](b); Result := Result.Concat(a); end; {function operator*(a: sequence of T; n: integer): sequence of T; extensionmethod; begin Result := System.Linq.Enumerable.Empty&(); loop n do Result := Result.Concat(a); end; function operator*(n: integer; a: sequence of T): sequence of T; extensionmethod; begin Result := a * n; end;} ///-- function operator in(x: T; Self: sequence of T): boolean; extensionmethod; begin Result := Self.Contains(x); end; // ----------------------------------------------------------------------------- // Функции для последовательностей и динамических массивов // ----------------------------------------------------------------------------- function Range(a, b: integer): sequence of integer; begin if b < a then Result := System.Linq.Enumerable.Empty& else Result := System.Linq.Enumerable.Range(a, b - a + 1); end; function PartitionPoints(a, b: real; n: integer): sequence of real; begin if n = 0 then raise new System.ArgumentException('Range: n = 0'); if n < 0 then raise new System.ArgumentException('Range: n < 0'); var r := a; var h := (b - a) / n; for var i := 0 to n do begin yield r; r += h end; end; function Range(c1, c2: char): sequence of char; begin Result := Range(integer(c1), integer(c2)).Select(x -> Chr(x)); end; function Range(c1, c2: char; step: integer): sequence of char; begin Result := Range(integer(c1), integer(c2), step).Select(x -> Chr(x)); end; function Range(a, b, step: BigInteger): sequence of BigInteger; begin if step = 0 then raise new System.ArgumentException('step = 0'); if step > 0 then while a<=b do begin yield a; a += step; end else while a>=b do begin yield a; a += step; end end; function Range(a, b: BigInteger): sequence of BigInteger := Range(a,b,1); type ArithmSeq = auto class a, step: integer; function f(x: integer): integer; begin Result := x * step + a; end; end; function Range(a, b, step: integer): sequence of integer; begin if step = 0 then raise new System.ArgumentException('step = 0'); if (step > 0) and (b < a) or (step < 0) and (b > a) then begin Result := System.Linq.Enumerable.Empty&; exit; end; var n := abs((b - a) div step) + 1; var ar: ArithmSeq; {if step<0 then ar := new ArithmSeq(b,step) else} ar := new ArithmSeq(a, step); Result := System.Linq.Enumerable.Range(0, n).Select(ar.f); end; function Range(a, b, step: real): sequence of real; begin if step = 0 then raise new System.ArgumentException('step = 0'); if (step > 0) and (b < a) or (step < 0) and (b > a) then exit; if a = b then begin yield a; exit; end; // SSM 30/06/24 // Шкалируем [a,b] к отрезку [0,1] var stepScaled := decimal(step) / (decimal(a) - decimal(b)); if stepScaled < 0 then stepScaled := -stepScaled; // Находим n - количество частей (левая точка последней части может не входить) var n := decimal.ToInt32(decimal.Round(1/stepScaled)); //Println('-->',stepScaled,n); // Возможны 3 ситуации: // 1) - stepScaled * n < 1 - 1e-14 - тогда надо делать n+1 шаг // 2) - stepScaled * n и диапазоне [1 - 1e-14, 1 + 1e-14] - тогда надо делать n+1 шаг и последнюю точку примагничивать к b // 3) - stepScaled * n > 1 + 1e-14 - тогда надо делать n шагов // Сделаем n шагов, а потом решим, делать ли последний шаг for var i:=0 to n-1 do yield a + i * step; // нельзя просто прибавлять step - при больших a,b они просто не будут меняться var delta := decimal(1e-14); // относительная погрешность относительно 1 if (stepScaled * n >= 1 - delta) and (stepScaled * n <= 1 + delta) then yield b // вернуть ровно b - то, ради чего всё затевалось else if stepScaled * n < 1 - delta then yield a + n * step; // что ж, step задан неверно и мы "не долетаем" до b // Если "перелетаем" b, то ничего и не возвращаем на конце // Старый алгоритм {var n := Round(Abs(b - a) / step); var delta := n / Abs(b - a) * 1e-14; var bplus := b + delta; var bminus := b - delta; if step > 0 then begin while a < bminus do begin yield a; a += step end; if a < bplus then yield b; end else begin while a > bplus do begin yield a; a += step end; if a > bminus then yield b; end} end; function ArrRandom(n: integer; a: integer; b: integer): array of integer; begin Result := new integer[n]; for var i := 0 to Result.Length - 1 do Result[i] := Random(a, b); end; function ArrRandomInteger(n: integer; a: integer; b: integer): array of integer; begin Result := ArrRandom(n, a, b); end; function ArrRandomInteger(n: integer) := ArrRandomInteger(n,0,100); function ArrRandomReal(n: integer; a: real; b: real; digits: integer): array of real; begin Result := new real[n]; for var i := 0 to Result.Length - 1 do Result[i] := RandomReal(a,b,digits); end; function ArrRandomReal(n: integer; digits: integer) := ArrRandomReal(n,0,10,digits); function SeqRandom(n: integer; a: integer; b: integer): sequence of integer; begin loop n do yield Random(a, b) end; function SeqRandomInteger(n: integer; a: integer; b: integer): sequence of integer; begin loop n do yield Random(a, b) end; function SeqRandomReal(n: integer; a: real; b: real; digits: integer): sequence of real; begin loop n do yield RandomReal(a,b,digits) end; function Arr(params a: array of T): array of T; begin Result := new T[a.Length]; if a.Length > 0 then System.Array.Copy(a, Result, a.Length); end; function Arr(a: sequence of T): array of T; begin Result := a.ToArray; end; function Arr(a: IntRange): array of integer := a.ToArray; function Arr(a: CharRange): array of char; begin var n := integer(a.High) - integer(a.Low) + 1; Result := new char[n]; var x := a.Low; for var i := 0 to n-1 do begin Result[i] := x; Inc(x) end; end; function Seq(params a: array of T): sequence of T; begin var res := new T[a.Length]; System.Array.Copy(a, res, a.Length); Result := res; end; /// Возвращает бесконечную рекуррентную последовательность элементов, задаваемую начальным элементом first и функцией next function Iterate(first: T; next: T->T): sequence of T; begin yield first; while True do begin first := next(first); yield first; end; end; /// Возвращает бесконечную рекуррентную последовательность элементов, задаваемую начальными элементами first, second и функцией next function Iterate(first, second: T; next: (T,T)->T): sequence of T; begin yield first; yield second; while True do begin var nxt := next(first, second); yield nxt; first := second; second := nxt; end; end; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; fun: (T,T1) -> TRes): sequence of TRes; begin var aen := a.GetEnumerator; var ben := b.GetEnumerator; while aen.MoveNext and ben.MoveNext do yield fun(aen.Current,ben.Current) end; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; fun: (T,T1,T2) -> TRes): sequence of TRes; begin var aen := a.GetEnumerator; var ben := b.GetEnumerator; var cen := c.GetEnumerator; while aen.MoveNext and ben.MoveNext and cen.MoveNext do yield fun(aen.Current,ben.Current,cen.Current) end; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; fun: (T,T1,T2,T3) -> TRes): sequence of TRes; begin var aen := a.GetEnumerator; var ben := b.GetEnumerator; var cen := c.GetEnumerator; var den := d.GetEnumerator; while aen.MoveNext and ben.MoveNext and cen.MoveNext and den.MoveNext do yield fun(aen.Current,ben.Current,cen.Current,den.Current) end; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; fun: (T,T1,T2,T3,T4) -> TRes): sequence of TRes; begin var aen := a.GetEnumerator; var ben := b.GetEnumerator; var cen := c.GetEnumerator; var den := d.GetEnumerator; var een := e.GetEnumerator; while aen.MoveNext and ben.MoveNext and cen.MoveNext and den.MoveNext and een.MoveNext do yield fun(aen.Current,ben.Current,cen.Current,den.Current,een.Current) end; /// Объединяет две последовательности в последовательность двухэлементных кортежей function Zip(a: sequence of T; b: sequence of T1): sequence of (T, T1) := Zip(a,b,(ax,bx) -> (ax,bx)); /// Объединяет три последовательности в последовательность трехэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2) := Zip(a,b,c,(ax,bx,cx) -> (ax,bx,cx)); /// Объединяет четыре последовательности в последовательность четырехэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3) := Zip(a,b,c,d,(ax,bx,cx,dx) -> (ax,bx,cx,dx)); /// Объединяет пять последовательностей в последовательность пятиэлементных кортежей function Zip(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4) := Zip(a,b,c,d,e,(ax,bx,cx,dx,ex) -> (ax,bx,cx,dx,ex)); /// Возвращает декартово произведение последовательностей, проектируя каждую пару на значение function Cartesian(a: sequence of T; b: sequence of T1; func: (T,T1)->TRes): sequence of TRes; begin foreach var xa in a do foreach var xb in b do yield func(xa, xb) end; /// Возвращает декартово произведение последовательностей, проектируя каждую тройку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; func: (T,T1,T2)->TRes): sequence of TRes; begin foreach var xa in a do foreach var xb in b do foreach var xc in c do yield func(xa, xb, xc) end; /// Возвращает декартово произведение последовательностей, проектируя каждую четвёрку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; func: (T,T1,T2,T3)->TRes): sequence of TRes; begin foreach var xa in a do foreach var xb in b do foreach var xc in c do foreach var xd in d do yield func(xa, xb, xc, xd) end; /// Возвращает декартово произведение последовательностей, проектируя каждую пятёрку на значение function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; func: (T,T1,T2,T3,T4)->TRes): sequence of TRes; begin foreach var xa in a do foreach var xb in b do foreach var xc in c do foreach var xd in d do foreach var xe in e do yield func(xa, xb, xc, xd, xe) end; /// Возвращает декартово произведение последовательностей в виде последовательности пар function Cartesian(a: sequence of T; b: sequence of T1): sequence of (T, T1) := Cartesian(a,b,(xa,xb) -> (xa,xb)); /// Возвращает декартово произведение последовательностей в виде последовательности троек function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2) := Cartesian(a,b,c,(xa,xb,xc) -> (xa,xb,xc)); /// Возвращает декартово произведение последовательностей в виде последовательности четвёрок function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3) := Cartesian(a,b,c,d,(xa,xb,xc,xd) -> (xa,xb,xc,xd)); /// Возвращает декартово произведение последовательностей в виде последовательности пятёрок function Cartesian(a: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4) := Cartesian(a,b,c,d,e,(xa,xb,xc,xd,xe) -> (xa,xb,xc,xd,xe)); function SeqGen(count: integer; first: T; next: T->T): sequence of T; begin if count < 1 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_0)); Result := Iterate(first, next).Take(count); end; function SeqGen(count: integer; first, second: T; next: (T,T) ->T): sequence of T; begin if count < 1 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_0)); Result := Iterate(first, second, next).Take(count); end; function SeqWhile(first: T; next: T->T; pred: T->boolean): sequence of T; begin Result := Iterate(first, next).TakeWhile(pred); end; function SeqWhile(first, second: T; next: (T,T) ->T; pred: T->boolean): sequence of T; begin Result := Iterate(first, second, next).TakeWhile(pred); end; function ArrGen(count: integer; first: T; next: T->T): array of T; begin if count < 1 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_0)); var a := new T[count]; a[0] := first; for var i := 1 to a.Length - 1 do a[i] := next(a[i - 1]); Result := a; end; function ArrGen(count: integer; first, second: T; next: (T,T) ->T): array of T; begin if count < 2 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_1)); var a := new T[count]; a[0] := first; a[1] := second; for var i := 2 to a.Length - 1 do a[i] := next(a[i - 2], a[i - 1]); Result := a; end; {function ArrTransform(a: array of T; convert: T->T1): array of T1; begin var n := a.Length; var a1 := new T1[n]; for var i:=0 to n-1 do a1[i] := convert(a[i]); Result := a1; end; function ArrFilter(a: array of T; condition: T->boolean): array of T; begin var n := a.Length; var a1 := new T[n]; var j := 0; for var i:=0 to n-1 do if condition(a[i]) then begin a1[j] := a[i]; j += 1; end; SetLength(a1,j); Result := a1; end;} function ArrFill(count: integer; x: T): array of T; begin Result := new T[count]; for var i := 0 to Result.Length - 1 do Result[i] := x; end; function ArrGen(count: integer; gen: integer->T; from: integer): array of T; begin Result := new T[count]; for var i := 0 to Result.Length - 1 do Result[i] := gen(i + from); end; function ArrGen(count: integer; gen: integer->T): array of T; begin Result := new T[count]; for var i := 0 to Result.Length - 1 do Result[i] := gen(i); end; function SeqFill(count: integer; x: T): sequence of T; begin Result := System.Linq.Enumerable.Repeat(x, count); end; function SeqGen(count: integer; f: integer->T; from: integer): sequence of T; begin Result := Range(from, count + from - 1).Select(f) end; function SeqGen(count: integer; f: integer->T): sequence of T; begin Result := Range(0, count - 1).Select(f) end; function ReadArrInteger(n: integer): array of integer; begin Result := new integer[n]; for var i := 0 to Result.Length - 1 do Result[i] := ReadInteger; end; function ReadArrInt64(n: integer): array of int64; begin Result := new int64[n]; for var i := 0 to Result.Length - 1 do Result[i] := ReadInt64; end; function ReadArrInteger(prompt: string; n: integer): array of integer; begin Print(prompt); Result := ReadArrInteger(n); end; function ReadArrReal(n: integer): array of real; begin Result := new real[n]; for var i := 0 to Result.Length - 1 do Result[i] := ReadReal; end; function ReadArrReal(prompt: string; n: integer): array of real; begin Print(prompt); Result := ReadArrReal(n); end; function ReadArrString(n: integer): array of string; begin Result := new string[n]; for var i := 0 to Result.Length - 1 do Result[i] := ReadString; end; function ReadArrString(prompt: string; n: integer): array of string; begin Print(prompt); Result := ReadArrString(n); end; ///-- function ReadArrInteger: array of integer; begin Result := nil; raise new System.ArgumentException('Функцию ReadArrInteger запрещено вызывать без параметров') end; ///-- function ReadArrReal: array of real; begin Result := nil; raise new System.ArgumentException('Функцию ReadArrReal запрещено вызывать без параметров') end; ///-- function ReadArrString: array of string; begin Result := nil; raise new System.ArgumentException('Функцию ReadArrString запрещено вызывать без параметров') end; function ArrEqual(a, b: array of T): boolean; begin Result := True; if a.Length<>b.Length then Result := False else for var i:=0 to a.Length-1 do if a[i]<>b[i] then begin Result := False; exit; end; end; function ReadSeqInteger(n: integer): sequence of integer; begin Result := Range(1, n).Select(i -> ReadInteger()); end; function ReadSeqInteger(prompt: string; n: integer): sequence of integer; begin Print(prompt); Result := ReadSeqInteger(n); end; function ReadSeqReal(n: integer): sequence of real; begin Result := Range(1, n).Select(i -> ReadReal()); end; function ReadSeqReal(prompt: string; n: integer): sequence of real; begin Print(prompt); Result := ReadSeqReal(n); end; function ReadSeqString(n: integer): sequence of string; begin Result := Range(1, n).Select(i -> ReadString()); end; function ReadSeqString(prompt: string; n: integer): sequence of string; begin Print(prompt); Result := ReadSeqString(n); end; function ReadSeqIntegerWhile(cond: integer->boolean): sequence of integer; begin while True do begin var x := ReadInteger(); if not cond(x) then break; yield x; end; end; function ReadSeqRealWhile(cond: real->boolean): sequence of real; begin while True do begin var x := ReadReal(); if not cond(x) then break; yield x; end; end; function ReadSeqStringWhile(cond: string->boolean): sequence of string; begin while True do begin var x := ReadString(); if not cond(x) then break; yield x; end; end; function ReadSeqIntegerWhile(prompt: string; cond: integer->boolean): sequence of integer; begin Print(prompt); Result := ReadSeqIntegerWhile(cond); end; function ReadSeqRealWhile(prompt: string; cond: real->boolean): sequence of real; begin Print(prompt); Result := ReadSeqRealWhile(cond); end; function ReadSeqStringWhile(prompt: string; cond: string->boolean): sequence of string; begin Print(prompt); Result := ReadSeqStringWhile(cond); end; // ----------------------------------------------------------------------------- // Функции Rec для создания кортежей // ----------------------------------------------------------------------------- function Rec(x1: T1; x2: T2) := Tuple.Create(x1, x2); function Rec(x1: T1; x2: T2; x3: T3) := Tuple.Create(x1, x2, x3); function Rec(x1: T1; x2: T2; x3: T3; x4: T4) := Tuple.Create(x1, x2, x3, x4); function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5) := Tuple.Create(x1, x2, x3, x4, x5); function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5; x6: T6) := Tuple.Create(x1, x2, x3, x4, x5, x6); function Rec(x1: T1; x2: T2; x3: T3; x4: T4; x5: T5; x6: T6; x7: T7) := Tuple.Create(x1, x2, x3, x4, x5, x6, x7); // ----------------------------------------------------------------------------- // Функции Lst, LLst, Dict, KV, HSet, SSet // ----------------------------------------------------------------------------- function Lst(params a: array of T): List := new List(a); function Lst(a: sequence of T): List := new List(a); function Lst(a: IntRange): List := a.ToList; function Lst(a: CharRange): List := a.ToList; function LstStr(params a: array of string): List := a.ToList; function LstInt(params a: array of integer): List := a.ToList; function LLst(params a: array of T): LinkedList := new LinkedList(a); function LLst(a: sequence of T): LinkedList := new LinkedList(a); function HSet(params a: array of T): HashSet := new HashSet(a); function SSet(params a: array of T): SortedSet := new SortedSet(a); function HSet(a: sequence of T): HashSet := new HashSet(a); function SSet(a: sequence of T): SortedSet := new SortedSet(a); function HSetInt(params a: array of integer): HashSet := new HashSet(a); function HSetStr(params a: array of string): HashSet := new HashSet(a); function SSetInt(params a: array of integer): SortedSet := new SortedSet(a); function SSetStr(params a: array of string): SortedSet := new SortedSet(a); function HSet(a: IntRange): HashSet := new HashSet(a); function HSet(a: CharRange): HashSet := new HashSet(a); function SetOf(params a: array of T): NewSet; begin Result._hs := new HashSet(a); end; function Dict(params pairs: array of KeyValuePair): Dictionary; begin Result := new Dictionary(); for var i := 0 to pairs.Length - 1 do Result.Add(pairs[i].Key, pairs[i].Value); end; function Dict(params pairs: array of (TKey, TVal)): Dictionary; begin Result := new Dictionary(); for var i := 0 to pairs.Length - 1 do Result.Add(pairs[i][0], pairs[i][1]); end; function Dict(pairs: sequence of KeyValuePair): Dictionary := Dict(pairs.ToArray); function Dict(pairs: sequence of (TKey, TVal)): Dictionary := Dict(pairs.ToArray); function Dict(keys: sequence of TKey; values: sequence of TVal): Dictionary := Dict(keys.Zip(values, (k,v) -> KV(k,v))); function KV(key: TKey; value: TVal): KeyValuePair := new KeyValuePair(key, value); function Pair(key: TKey; value: TVal): KeyValuePair := new KeyValuePair(key, value); function DictStr(params pairs: array of (string, string)): Dictionary := Dict&(pairs); function DictStrInt(params pairs: array of (string, integer)): Dictionary := Dict&(pairs); function DictInt(params pairs: array of (integer, integer)): Dictionary := Dict&(pairs); function __TypeCheckAndAssignForIsMatch(obj: object; var res: T): boolean; begin if obj is T then begin res := T(obj); Result := true; end else begin res := default(T); Result := false; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); end; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); 2: Result := Result and first.Item3.Equals(second.Item3); end; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); 2: Result := Result and first.Item3.Equals(second.Item3); 3: Result := Result and first.Item4.Equals(second.Item4); end; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); 2: Result := Result and first.Item3.Equals(second.Item3); 3: Result := Result and first.Item4.Equals(second.Item4); 4: Result := Result and first.Item5.Equals(second.Item5); end; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); 2: Result := Result and first.Item3.Equals(second.Item3); 3: Result := Result and first.Item4.Equals(second.Item4); 4: Result := Result and first.Item5.Equals(second.Item5); 5: Result := Result and first.Item6.Equals(second.Item6); end; end; end; function __WildCardsTupleEqual( first: Tuple; second: Tuple; elemsToCompare: sequence of integer): boolean; begin Result := True; foreach var ind in elemsToCompare do begin case ind of 0: Result := Result and first.Item1.Equals(second.Item1); 1: Result := Result and first.Item2.Equals(second.Item2); 2: Result := Result and first.Item3.Equals(second.Item3); 3: Result := Result and first.Item4.Equals(second.Item4); 4: Result := Result and first.Item5.Equals(second.Item5); 5: Result := Result and first.Item6.Equals(second.Item6); 6: Result := Result and first.Item7.Equals(second.Item7); end; end; end; ///-- procedure Deconstruct(self: T; var res: T); extensionmethod; begin res := self; end; // ----------------------------------------------------- // IOStandardSystem: implementation // ----------------------------------------------------- constructor IOStandardSystem.Create; begin tr := Console.In; //buf := new char[buflen]; - теперь при объявлении поля end; const m = char(-1); procedure IOStandardSystem.ReadNextBuf; begin realbuflen := tr.Read{Block}(buf, 0, buflen); // SSM 29/03/22 #2647 if realbuflen < buflen then buf[realbuflen] := char(-1); pos := 0; end; procedure IOStandardSystem.ReadNextConsoleBuf; begin var sbuf := Console.ReadLine + NewLine; read_buf := sbuf.ToCharArray; rbpos := 0; rblen := read_buf.Length; end; var _IsPipedRedirectedQuery := False; _IsPipedRedirected := False; function IsInputPipedOrRedirectedFromFile: boolean; begin if _IsPipedRedirectedQuery then Result := _IsPipedRedirected else begin _IsPipedRedirectedQuery := True; var pi := typeof(Console).GetProperty('IsInputRedirected'); if pi = nil then begin _IsPipedRedirected := False; // просто работаем без буфера на старых системах Result := _IsPipedRedirected; end else begin var IsInputRedirected := boolean(pi?.GetValue(nil,nil)); _IsPipedRedirected := IsInputRedirected {Console.IsInputRedirected} and (CurrentIOSystem.GetType = typeof(IOStandardSystem)); Result := _IsPipedRedirected; end; end; end; function IOStandardSystem.peek: integer;// + begin if IsInputPipedOrRedirectedFromFile then begin// новый код if pos >= realbuflen then ReadNextBuf; Result := integer(buf[pos]); end else // старый код begin if not console_alloc then AllocConsole; // SSM 29.11.14 {if state = 1 then // в sym - символ, считанный предыдущим Peek Result := sym else // в sym ничего нет begin state := 1; sym := Console.Read(); // считываение в буфер из одного символа Result := sym; end; } // SSM 28.02.23 if rbpos >= rblen then // буфер строки пуст ReadNextConsoleBuf; Result := integer(read_buf[rbpos]); end; end; function IOStandardSystem.read_symbol: char;// + begin if IsInputPipedOrRedirectedFromFile then begin// новый код if pos >= realbuflen then ReadNextBuf; Result := buf[pos]; if Result <> m then pos += 1; end else // старый код begin if not console_alloc then AllocConsole; // SSM 29.11.14 {if state = 1 then // в sym - символ, считанный предыдущим Peek begin state := 0; Result := char(sym); sym := -1; end else // в sym ничего нет Result := char(Console.Read()); exit;} // SSM 28.02.23 if rbpos >= rblen then // буфер строки пуст ReadNextConsoleBuf; Result := read_buf[rbpos]; rbpos += 1; end; end; function IOStandardSystem.ReadLine: string;// + begin {ReadNextBuf; while realbuflen>0 do begin sb.Append(buf,0,realbuflen); ReadNextBuf; end;} if IsInputPipedOrRedirectedFromFile then begin// новый код {var sb := new StringBuilder(10); // старый новый код var c: char; repeat if pos >= realbuflen then ReadNextBuf; c := buf[pos]; if c = char(-1) then break; pos += 1; if c = #13 then break; if c = #10 then break; sb.Append(c); until False; if c = #13 then begin if peek = 10 then read_symbol; end; Result := sb.ToString;} var sb := new StringBuilder(10); // новый новый код var c: char; repeat if pos >= realbuflen then break; c := buf[pos]; if c = char(-1) then break; pos += 1; if c = #13 then break; if c = #10 then break; sb.Append(c); until False; if pos >= realbuflen then // Если дочитали до конца буфера, то вернуть sb.ToString + tr.ReadLine begin Result := sb.ToString + tr.ReadLine; ReadNextBuf; end else // Если мы не дочитали до конца буфера, то просто вернуть sb.ToString begin Result := sb.ToString; if c = #13 then begin if peek = 10 then read_symbol; end; end; end else // старый код begin if not console_alloc then AllocConsole; {if state = 1 then begin state := 0; Result := char(sym) + Console.ReadLine; sym := -1; end else Result := Console.ReadLine;} // SSM 28.02.23 if rbpos >= rblen then // буфер строки пуст ReadNextConsoleBuf; // Проблема - там может уже оставаться 1 или 2 символа. Если так, то строка будет пустой! var remlen := rblen - rbpos - NewLine.Length; if remlen <= 0 then Result := '' else Result := string.Create(read_buf,rbpos,remlen); rbpos := rblen; end; end; function ReadLexem: string; begin {if input.sr <> nil then Result := ReadLexem(input) else} Result := CurrentIOSystem.ReadLexem; end; function IOStandardSystem.ReadLexem: string; begin if IsInputPipedOrRedirectedFromFile then begin// новый код var c: char; repeat c := read_symbol; until (c <> ' ') and (c <> #10) and (c <> #13) and (c <> #9); if c = char(-1) then raise new System.IO.IOException(GetTranslation(READ_LEXEM_AFTER_END_OF_INPUT_STREAM)); var sb := new StringBuilder; repeat sb.Append(c); if pos >= realbuflen then ReadNextBuf; c := buf[pos]; //c := read_symbol; if c = ' ' then break; if c = #10 then break; if c = #13 then break; if c = #9 then break; if c = char(-1) then break; pos += 1; until False; Result := sb.ToString; end else // старый код begin var c: char; repeat c := read_symbol; until not char.IsWhiteSpace(c); var sb := new System.Text.StringBuilder; repeat sb.Append(c); c := char(peek); if char.IsWhiteSpace(c) or (c = char(-1)) then // char(-1) - Ctrl-Z во входном потоке break; c := read_symbol; until False; // accumulate nonspaces Result := sb.ToString; end; end; {function ErrorStringFromResource(s: string): string; begin //var _rm := new System.Resources.ResourceManager('mscorlib', typeof(object).Assembly); //Result := _rm.GetString(s); Result := GetTranslation(s); end;} procedure IOStandardSystem.read(var x: integer); begin if IsInputPipedOrRedirectedFromFile then begin// новый код var c: char; repeat c := read_symbol; until (c <> ' ') and (c <> #10) and (c <> #13) and (c <> #9); if c = char(-1) then raise new System.IO.IOException(GetTranslation(READ_LEXEM_AFTER_END_OF_INPUT_STREAM)); var sign := 0; if c = '-' then begin sign := -1; c := read_symbol; end else if c = '+' then begin sign := 1; c := read_symbol; end; if c = char(-1) then raise new System.IO.IOException(GetTranslation(READ_LEXEM_AFTER_END_OF_INPUT_STREAM)); if (c < #48) or (c > #57) then raise new System.FormatException(GetTranslation(Format_InvalidString) + ' ' + Ord(c)); x := integer(c) - 48; repeat if pos >= realbuflen then ReadNextBuf; c := buf[pos]; //c := read_symbol; if c = ' ' then break; if c = #10 then break; if c = #13 then break; if c = #9 then break; if c = char(-1) then break; if c > #57 then raise new System.FormatException(GetTranslation(Format_InvalidString) + ' ' + Ord(c)); if c < #48 then raise new System.FormatException(GetTranslation(Format_InvalidString) + ' ' + Ord(c)); if x > 214748364 then raise new System.OverflowException(GetTranslation(Overflow_Int32)); x := x * 10 + (integer(c) - 48); pos += 1; until False; if x < 0 then if (x = -2147483648) and (sign = -1) then exit else raise new System.OverflowException(GetTranslation(Overflow_Int32)); if sign = -1 then x := -x; end else // старый код begin x := StrToInt(ReadLexem); end; end; procedure IOStandardSystem.read(var x: real); begin x := Convert.ToDouble(ReadLexem, nfi); end; procedure IOStandardSystem.read(var x: char); begin x := read_symbol; end; procedure IOStandardSystem.read(var x: string); begin var sb := new StringBuilder; // SSM 8.04.10 var c := char(peek()); // первый раз может быть char(-1) - это значит, что в потоке ввода ничего нет, тогда мы читаем символ while (c <> #13) and (c <> #10) do begin c := read_symbol; if (c <> #13) and (c <> #10) then // SSM 13.12.13 sb.Append(c); c := char(peek); if c = char(-1) then break; end; x := sb.ToString; end; procedure IOStandardSystem.read(var x: byte); begin x := Convert.ToByte(ReadLexem); end; procedure IOStandardSystem.read(var x: shortint); begin x := Convert.ToSByte(ReadLexem); end; procedure IOStandardSystem.read(var x: smallint); begin x := Convert.ToInt16(ReadLexem); end; procedure IOStandardSystem.read(var x: word); begin x := Convert.ToUInt16(ReadLexem); end; procedure IOStandardSystem.read(var x: longword); begin x := Convert.ToUInt32(ReadLexem); end; procedure IOStandardSystem.read(var x: int64); begin x := Convert.ToInt64(ReadLexem); end; procedure IOStandardSystem.read(var x: uint64); begin x := Convert.ToUInt64(ReadLexem); end; procedure IOStandardSystem.read(var x: single); begin x := Convert.ToSingle(ReadLexem, nfi); end; procedure IOStandardSystem.read(var x: boolean); begin var s := ReadLexem.ToLower; if s = 'true' then x := True else if s = 'false' then x := False else raise new System.FormatException('Входная строка имела неверный формат'); end; procedure IOStandardSystem.read(var x: BigInteger); begin x := Biginteger.Parse(ReadLexem) end; procedure IOStandardSystem.readln; begin // while CurrentIOSystem.read_symbol <> END_OF_LINE_SYMBOL do; // было while True do begin var sym := CurrentIOSystem.read_symbol; if (sym = END_OF_LINE_SYMBOL) or (sym = char(-1)) then exit; end; end; {function IOStandardSystem.ReadLine: string; begin // Надо учесть sym if not console_alloc then AllocConsole; if state = 1 then begin state := 0; Result := char(sym) + Console.ReadLine; sym := -1; end else Result := Console.ReadLine; end;} procedure IOStandardSystem.write(obj: object); begin if not console_alloc then AllocConsole; Console.Write(ObjectToString(obj)); end; procedure IOStandardSystem.write(p: pointer); begin Write(PointerToString(p)); end; procedure IOStandardSystem.writeln; begin if not console_alloc then AllocConsole; Console.WriteLine; System.Diagnostics.Debug.WriteLine(''); end; // ----------------------------------------------------- // Read - Readln // ----------------------------------------------------- procedure Read; begin end; procedure Readln; begin CurrentIOSystem.readln end; procedure Read(var x: integer); begin CurrentIOSystem.read(x) end; procedure Read(var x: real); begin CurrentIOSystem.read(x) end; procedure Read(var x: char); begin CurrentIOSystem.read(x) end; procedure Read(var x: string); begin CurrentIOSystem.read(x) end; procedure Read(var x: byte); begin CurrentIOSystem.read(x) end; procedure Read(var x: shortint); begin CurrentIOSystem.read(x) end; procedure Read(var x: smallint); begin CurrentIOSystem.read(x) end; procedure Read(var x: word); begin CurrentIOSystem.read(x) end; procedure Read(var x: longword); begin CurrentIOSystem.read(x) end; procedure Read(var x: int64); begin CurrentIOSystem.read(x) end; procedure Read(var x: uint64); begin CurrentIOSystem.read(x) end; procedure Read(var x: single); begin CurrentIOSystem.read(x) end; procedure Read(var x: boolean); begin CurrentIOSystem.read(x) end; procedure Read(var x: BigInteger); begin CurrentIOSystem.read(x) end; function TryRead(var x: integer; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: BigInteger; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: real; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: byte; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: shortint; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: smallint; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: word; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: longword; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: int64; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: uint64; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: single; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function TryRead(var x: boolean; message: string): boolean; begin Result := True; try if message<>'' then Print(message); Read(x) except Result := False; end end; function ReadInteger: integer; begin Read(Result); end; function ReadInt64: int64; begin Read(Result); end; function ReadReal: real; begin Read(Result); end; function ReadChar: char; begin Read(Result); end; function ReadString: string; begin Result := CurrentIOSystem.ReadLine; end; function ReadBoolean: boolean; begin Read(Result); end; function ReadBigInteger: BigInteger; begin Read(Result); end; function ReadlnInteger: integer; begin Result := ReadInteger; Readln(); end; function ReadlnInt64: int64; begin Result := ReadInt64; Readln(); end; function ReadlnReal: real; begin Result := ReadReal; Readln(); end; function ReadlnChar: char; begin Result := ReadChar; Readln(); end; function ReadlnString: string; begin Result := CurrentIOSystem.ReadLine; end; function ReadlnBoolean: boolean; begin Result := ReadBoolean; Readln(); end; function ReadlnBigInteger: BigInteger; begin Result := ReadBigInteger; Readln(); end; function ReadInteger2 := (ReadInteger, ReadInteger); function ReadReal2 := (ReadReal, ReadReal); function ReadChar2 := (ReadChar, ReadChar); function ReadString2 := (ReadString, ReadString); function ReadlnInteger2 := (ReadInteger, ReadlnInteger); function ReadlnReal2 := (ReadReal, ReadlnReal); function ReadlnChar2 := (ReadChar, ReadlnChar); function ReadlnString2 := (ReadString, ReadlnString); function ReadInteger3 := (ReadInteger, ReadInteger, ReadInteger); function ReadReal3 := (ReadReal, ReadReal, ReadReal); function ReadChar3 := (ReadChar, ReadChar, ReadChar); function ReadString3 := (ReadString, ReadString, ReadString); function ReadlnInteger3 := (ReadInteger, ReadInteger, ReadlnInteger); function ReadlnReal3 := (ReadReal, ReadReal, ReadlnReal); function ReadlnChar3 := (ReadChar, ReadChar, ReadlnChar); function ReadlnString3 := (ReadString, ReadString, ReadlnString); function ReadInteger4 := (ReadInteger, ReadInteger, ReadInteger, ReadInteger); function ReadReal4 := (ReadReal, ReadReal, ReadReal, ReadReal); function ReadChar4 := (ReadChar, ReadChar, ReadChar, ReadChar); function ReadString4 := (ReadString, ReadString, ReadString, ReadString); function ReadlnInteger4 := (ReadInteger, ReadInteger, ReadInteger, ReadlnInteger); function ReadlnReal4 := (ReadReal, ReadReal, ReadReal, ReadlnReal); function ReadlnChar4 := (ReadChar, ReadChar, ReadChar, ReadlnChar); function ReadlnString4 := (ReadString, ReadString, ReadString, ReadlnString); function ReadInteger2(prompt: string) := (ReadInteger(prompt), ReadInteger); function ReadReal2(prompt: string) := (ReadReal(prompt), ReadReal); function ReadChar2(prompt: string) := (ReadChar(prompt), ReadChar); function ReadString2(prompt: string) := (ReadString(prompt), ReadString); function ReadlnInteger2(prompt: string) := (ReadInteger(prompt), ReadlnInteger); function ReadlnReal2(prompt: string) := (ReadReal(prompt), ReadlnReal); function ReadlnChar2(prompt: string) := (ReadChar(prompt), ReadlnChar); function ReadlnString2(prompt: string) := (ReadString(prompt), ReadlnString); function ReadInteger3(prompt: string) := (ReadInteger(prompt), ReadInteger, ReadInteger); function ReadReal3(prompt: string) := (ReadReal(prompt), ReadReal, ReadReal); function ReadChar3(prompt: string) := (ReadChar(prompt), ReadChar, ReadChar); function ReadString3(prompt: string) := (ReadString(prompt), ReadString, ReadString); function ReadlnInteger3(prompt: string) := (ReadInteger(prompt), ReadInteger, ReadlnInteger); function ReadlnReal3(prompt: string) := (ReadReal(prompt), ReadReal, ReadlnReal); function ReadlnChar3(prompt: string) := (ReadChar(prompt), ReadChar, ReadlnChar); function ReadlnString3(prompt: string) := (ReadString(prompt), ReadString, ReadlnString); function ReadInteger4(prompt: string) := (ReadInteger(prompt), ReadInteger, ReadInteger, ReadInteger); function ReadReal4(prompt: string) := (ReadReal(prompt), ReadReal, ReadReal, ReadReal); function ReadChar4(prompt: string) := (ReadChar(prompt), ReadChar, ReadChar, ReadChar); function ReadString4(prompt: string) := (ReadString(prompt), ReadString, ReadString, ReadString); function ReadlnInteger4(prompt: string) := (ReadInteger(prompt), ReadInteger, ReadInteger, ReadlnInteger); function ReadlnReal4(prompt: string) := (ReadReal(prompt), ReadReal, ReadReal, ReadlnReal); function ReadlnChar4(prompt: string) := (ReadChar(prompt), ReadChar, ReadChar, ReadlnChar); function ReadlnString4(prompt: string) := (ReadString(prompt), ReadString, ReadString, ReadlnString); // Read with prompt function ReadInteger(prompt: string): integer; begin Print(prompt); Result := ReadInteger; end; function ReadInt64(prompt: string): int64; begin Print(prompt); Result := ReadInt64; end; function ReadReal(prompt: string): real; begin Print(prompt); Result := ReadReal; end; function ReadChar(prompt: string): char; begin Print(prompt); Result := ReadChar; end; function ReadString(prompt: string): string; begin Print(prompt); Result := ReadString; end; function ReadBoolean(prompt: string): boolean; begin Print(prompt); Result := ReadBoolean; end; function ReadBigInteger(prompt: string) : BigInteger; begin Print(prompt); Result := ReadBigInteger; end; function ReadlnInteger(prompt: string): integer; begin Print(prompt); Result := ReadlnInteger; end; function ReadlnInt64(prompt: string): int64; begin Print(prompt); Result := ReadlnInt64; end; function ReadlnReal(prompt: string): real; begin Print(prompt); Result := ReadlnReal; end; function ReadlnChar(prompt: string): char; begin Print(prompt); Result := ReadlnChar; end; function ReadlnString(prompt: string): string; begin Print(prompt); Result := ReadlnString; end; function ReadlnBoolean(prompt: string): boolean; begin Print(prompt); Result := ReadlnBoolean; end; function ReadlnBigInteger(prompt: string): BigInteger; begin Print(prompt); Result := ReadlnInteger; end; procedure ReadShortStringFromFile(f: Text; var s: string; n: integer); begin //x := f.sr.ReadLine;//если конец файла то вернет nil //Нельзя эти пользоваться т.к. считывает и конец строки var i := 1; var sb := new System.Text.StringBuilder; repeat if f.sr.EndOfStream then break; if f.sr.Peek = 13 then break; if f.sr.Peek = 10 then break; if i > n then break; sb.Append(Convert.ToChar(f.sr.Read)); i := i + 1; until False; s := sb.ToString; {} if s = nil then s := string.Empty; if s.Length > n then s := s.Substring(0, n); end; procedure ReadShortString(var s: string; n: integer);// Снова сделал peek. В прошлый раз была ошибка begin // SSM 30/01/20 - закомментировал это, поскольку мы перешли на буфер, и read_symbol и peek сами переключают потоки при Assign(input,...) и считывают из буфера {if (input.fi <> nil) and (input.sr <> nil) then begin ReadShortStringFromFile(input, s, n); exit; end;} { var sb := new System.Text.StringBuilder; var c := CurrentIOSystem.read_symbol; while c <> #13 do begin sb.Append(c); c := CurrentIOSystem.read_symbol; end; s := sb.ToString; if s.Length > n then s := s.Substring(0, n); } // SSM 8.04.10 var sb := new System.Text.StringBuilder; var c := char(CurrentIOSystem.peek()); var i := 0; while (c <> #13) and (c <> #10) and (i < n) do begin c := CurrentIOSystem.read_symbol; i += 1; sb.Append(c); c := char(CurrentIOSystem.peek()); end; s := sb.ToString; end; //-------------------------------- procedure read(f: Text); begin end; procedure readln(f: Text); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_READING)); f.sr.ReadLine; end; procedure read(f: Text; var x: integer); begin try x := Convert.ToInt32(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: real); begin try x := Convert.ToDouble(ReadLexem(f), nfi); except on e: Exception do raise e; end; end; procedure readln(f: Text; var x: string); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_READING)); x := f.sr.ReadLine; if x = nil then x := ''; end; procedure read(f: Text; var x: string); begin //x := f.sr.ReadLine;//если конец файла то вернет nil //Нельзя этим пользоваться т.к. считывает и конец строки if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_READING)); var s := new System.Text.StringBuilder; repeat if f.sr.EndOfStream then break; if f.sr.Peek = 13 then break; if f.sr.Peek = 10 then break; s.Append(Convert.ToChar(f.sr.Read)); until False; x := s.ToString; {} if x = nil then x := string.Empty; end; procedure read(f: Text; var x: char); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_READING)); try x := char(f.sr.Read()); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: byte); begin try x := Convert.ToByte(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: shortint); begin try x := Convert.ToSByte(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: smallint); begin try x := Convert.ToInt16(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: word); begin try x := Convert.ToUInt16(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: longword); begin try x := Convert.ToUInt32(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: int64); begin try x := Convert.ToInt64(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: uint64); begin try x := Convert.ToUInt64(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: single); begin try x := Convert.ToSingle(ReadLexem(f)); except on e: Exception do raise e; end; end; procedure read(f: Text; var x: boolean); begin var s := ReadLexem(f).ToLower; if s = 'true' then x := True else if s = 'false' then x := False else raise new System.FormatException('Входная строка имела неверный формат'); end; function ReadInteger(f: Text): integer; begin Read(f, Result); end; function ReadInt64(f: Text): int64; begin Read(f, Result); end; function ReadReal(f: Text): real; begin Read(f, Result); end; function ReadChar(f: Text): char; begin Read(f, Result); end; function ReadString(f: Text): string; begin Read(f, Result); Readln(f); end; function ReadBoolean(f: Text): boolean; begin Read(f, Result); end; function ReadlnInteger(f: Text): integer; begin Result := ReadInteger(f); Readln(f); end; function ReadlnInt64(f: Text): int64; begin Result := ReadInt64(f); Readln(f); end; function ReadlnReal(f: Text): real; begin Result := ReadReal(f); Readln(f); end; function ReadlnChar(f: Text): char; begin Result := ReadChar(f); Readln(f); end; function ReadlnString(f: Text): string; begin Result := ReadString(f); end; function ReadlnBoolean(f: Text): boolean; begin Result := ReadBoolean(f); Readln(f); end; function ReadLexem(f: Text): string; begin if f = input then begin Result := ReadLexem; exit end; if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_READING)); var i: integer; repeat i := f.sr.Read(); until not char.IsWhiteSpace(char(i)); // pass spaces if i=-1 then raise new System.IO.IOException(GetTranslation(READ_LEXEM_AFTER_END_OF_TEXT_FILE)); var c := char(i); var sb := System.Text.StringBuilder.Create; repeat sb.Append(c); i := f.sr.Peek(); if i = -1 then break; c := char(i); if char.IsWhiteSpace(c) then break; f.sr.Read(); until False; // accumulate nonspaces Result := sb.ToString; end; // ----------------------------------------------------- // TextFile methods // ----------------------------------------------------- function Text.ReadInteger := PABCSystem.ReadInteger(Self); function Text.ReadReal := PABCSystem.ReadReal(Self); function Text.ReadChar := PABCSystem.ReadChar(Self); function Text.ReadString := PABCSystem.ReadString(Self); function Text.ReadWord := ReadLexem(Self); function Text.ReadBoolean := PABCSystem.ReadBoolean(Self); function Text.ReadlnInteger := PABCSystem.ReadlnInteger(Self); function Text.ReadlnReal := PABCSystem.ReadlnReal(Self); function Text.ReadlnChar := PABCSystem.ReadlnChar(Self); function Text.ReadlnString := PABCSystem.ReadlnString(Self); function Text.ReadlnBoolean := PABCSystem.ReadlnBoolean(Self); procedure Text.Readln := PABCSystem.Readln(Self); procedure Text.Write(params o: array of Object) := PABCSystem.Write(Self, o); procedure Text.Writeln(params o: array of Object) := PABCSystem.Writeln(Self, o); procedure Text.Print(params o: array of Object); begin if PrintDelimDefault<>'' then foreach var s in o do PABCSystem.Write(Self, s, PrintDelimDefault) else foreach var s in o do PABCSystem.Write(Self, s) end; procedure Text.Println(params o: array of Object); begin if o.Length <> 0 then begin if PrintDelimDefault<>'' then for var i:=0 to o.Length-2 do PABCSystem.Write(Self, o[i], PrintDelimDefault) else for var i:=0 to o.Length-2 do PABCSystem.Write(Self, o[i]); PABCSystem.Write(Self, o.Last); end; PABCSystem.Writeln(Self); end; function Text.Eof := PABCSystem.Eof(Self); function Text.Eoln := PABCSystem.Eoln(Self); procedure Text.Close := PABCSystem.Close(Self); function Text.SeekEof := PABCSystem.SeekEof(Self); function Text.SeekEoln := PABCSystem.SeekEoln(Self); procedure Text.Flush := PABCSystem.Flush(Self); procedure Text.Erase := PABCSystem.Erase(Self); procedure Text.Rename(newname: string) := PABCSystem.Rename(Self, newname); function Text.Name := fi.Name; function Text.FullName := fi.FullName; function Text.ReadToEnd := sr.ReadToEnd; procedure Text.Reset := PABCSystem.Reset(Self); procedure Text.Reset(en: Encoding) := PABCSystem.Reset(Self,en); procedure Text.Rewrite := PABCSystem.Rewrite(Self); procedure Text.Rewrite(en: Encoding) := PABCSystem.Rewrite(Self,en); procedure Text.Append := PABCSystem.Append(Self); procedure Text.Append(en: Encoding) := PABCSystem.Append(Self,en); function Text.Lines: sequence of string; begin Self.sr.BaseStream.Position := 0; while not Eof do yield ReadlnString; end; // ----------------------------------------------------- // AbstractBinaryFile methods // ----------------------------------------------------- procedure AbstractBinaryFile.Close := PABCSystem.Close(Self); procedure AbstractBinaryFile.Truncate := PABCSystem.Truncate(Self); function AbstractBinaryFile.Eof := PABCSystem.Eof(Self); procedure AbstractBinaryFile.Erase := PABCSystem.Erase(Self); procedure AbstractBinaryFile.Rename(newname: string) := PABCSystem.Rename(Self, newname); procedure AbstractBinaryFile.Write(params vals: array of object) := PABCSystem.Write(Self, vals); procedure AbstractBinaryFile.Reset := PABCSystem.Reset(Self); procedure AbstractBinaryFile.Rewrite := PABCSystem.Rewrite(Self); function AbstractBinaryFile.Name := fi.Name; function AbstractBinaryFile.FullName := fi.FullName; // ----------------------------------------------------- // TypedFile & BinaryFile methods // ----------------------------------------------------- function TypedFile.Size: int64 := PABCSystem.FileSize(Self); function TypedFile.GetFilePos: int64 := PABCSystem.FilePos(Self); procedure TypedFile.Seek(n: int64) := PABCSystem.Seek(Self, n); procedure BinaryFile.Reset(en: Encoding) := PABCSystem.Reset(Self,en); procedure BinaryFile.Rewrite(en: Encoding) := PABCSystem.Rewrite(Self,en); function BinaryFile.GetFilePos: int64 := PABCSystem.FilePos(Self); function BinaryFile.Size: int64 := PABCSystem.FileSize(Self); procedure BinaryFile.Seek(n: int64) := PABCSystem.Seek(Self, n); procedure BinaryFile.InternalCheck; begin if Self.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if Self.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); end; procedure BinaryFile.WriteBytes(a: array of byte); begin InternalCheck; Self.bw.Write(a); end; function BinaryFile.ReadBytes(count: integer): array of byte; begin InternalCheck; Result := Self.br.ReadBytes(count) end; function BinaryFile.ReadInteger: integer; begin InternalCheck; Result := Self.br.ReadInt32; end; function BinaryFile.ReadBoolean: boolean; begin InternalCheck; Result := Self.br.ReadBoolean; end; function BinaryFile.ReadByte: byte; begin InternalCheck; Result := Self.br.ReadByte; end; function BinaryFile.ReadChar: char; begin InternalCheck; Result := Self.br.ReadChar; end; function BinaryFile.ReadReal: real; begin InternalCheck; Result := Self.br.ReadDouble; end; function BinaryFile.ReadString: string; begin InternalCheck; Result := Self.br.ReadString; end; procedure BinaryFile.Serialize(obj: object); begin var formatter := new BinaryFormatter; formatter.Serialize(fs,obj); end; function BinaryFile.Deserialize: object; begin var formatter := new BinaryFormatter; Result := formatter.Deserialize(fs); end; // ----------------------------------------------------- // Eoln - Eof // ----------------------------------------------------- function Eoln: boolean; begin if not console_alloc then AllocConsole; var next := CurrentIOSystem.peek; Result := (next = -1) or (next = 13) or (next = 10); //Result := CurrentIOSystem.peek = 13 end; function Eof: boolean; begin if not console_alloc then AllocConsole; Result := CurrentIOSystem.peek = -1 end; function SeekEof: boolean; begin repeat if Eof then break; var i := CurrentIOSystem.peek; if not char.IsWhiteSpace(char(i)) then break; CurrentIOSystem.read_symbol until False; Result := Eof; end; function SeekEoln: boolean; begin repeat if Eoln then break; var i := CurrentIOSystem.peek; if (i <> 32) and (i <> 9) then // Если это не пробел и не табуляция break; CurrentIOSystem.read_symbol; until False; var next := CurrentIOSystem.peek; Result := (next = -1) or (next = 13) or (next = 10); end; // ----------------------------------------------------- // CommandLineArgs # CommandLineArgs subroutine // ----------------------------------------------------- function CommandLineArgs: array of string; begin Result := _CommandLineArgs; if Result = nil then begin var arg := Environment.GetCommandLineArgs(); if arg.Length > 1 then begin _CommandLineArgs := new string[arg.Length - 1]; for var i := 1 to arg.Length - 1 do _CommandLineArgs[i - 1] := arg[i]; end else _CommandLineArgs := new string[0]; Result := _CommandLineArgs; end; end; // ----------------------------------------------------- // Write - Writeln # Write subroutines // ----------------------------------------------------- function PointerOutput.ToString: string; begin Result := PointerToString(p); end; constructor PointerOutput.Create(ptr: pointer); begin p := ptr; end; procedure Write; begin end; procedure write_in_output(obj: object); begin write(output, obj); end; procedure writeln_in_output; begin writeln(output); end; procedure Write(obj: object); begin if output.sw is StreamWriter then write_in_output(obj) else CurrentIOSystem.Write(obj); end; //procedure write(ptr: pointer); //begin // CurrentIOSystem.Write(ptr); //end; procedure Write(obj1, obj2: object); begin if output.sw is StreamWriter then begin write_in_output(obj1); write_in_output(obj2); end else begin CurrentIOSystem.Write(obj1); CurrentIOSystem.Write(obj2); end; end; procedure Write(params args: array of object); begin for var i := 0 to args.length - 1 do if output.sw is StreamWriter then write_in_output(args[i]) else CurrentIOSystem.Write(args[i]); end; procedure Writeln(obj: object); begin if output.sw is StreamWriter then begin write_in_output(obj); writeln_in_output; end else begin CurrentIOSystem.Write(obj); CurrentIOSystem.Writeln; end end; //procedure writeln(ptr: pointer); //begin // CurrentIOSystem.Write(PointerToString(ptr)); // CurrentIOSystem.Writeln; //end; procedure Writeln(obj1, obj2: object); begin if output.sw is StreamWriter then begin write_in_output(obj1); write_in_output(obj2); writeln_in_output; end else begin CurrentIOSystem.Write(obj1); CurrentIOSystem.Write(obj2); CurrentIOSystem.Writeln; end end; procedure Writeln; begin if output.sw is StreamWriter then writeln_in_output else CurrentIOSystem.Writeln; end; procedure Writeln(params args: array of object); begin if output.sw is StreamWriter then begin for var i := 0 to args.length - 1 do write_in_output(args[i]); writeln_in_output; end else begin for var i := 0 to args.length - 1 do CurrentIOSystem.Write(args[i]); CurrentIOSystem.Writeln; end; end; procedure Write(f: Text); begin end; procedure Write(f: Text; val: object); begin if (f.fi = nil) and (f<>output) and (f<>ErrOutput) then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sw = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_WRITING)); f.sw.Write(ObjectToString(val)); {if val = nil then begin f.sw.Write('nil'); exit; end; case System.Type.GetTypeCode(val.GetType) of TypeCode.Double, TypeCode.Single, TypeCode.Decimal: f.sw.Write(FormatFloatNumber(val.ToString)); else f.sw.Write(val) end;} end; procedure Write(f: Text; params args: array of object); begin for var i := 0 to args.length - 1 do write(f, args[i]); end; procedure Writeln(f: Text); begin if (f.fi = nil) and (f<>output) and (f<>ErrOutput) then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sw = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED_FOR_WRITING)); f.sw.WriteLine; end; procedure Writeln(f: Text; val: object); begin write(f, val); writeln(f); end; procedure Writeln(f: Text; params args: array of object); begin for var i := 0 to args.length - 1 do write(f, args[i]); writeln(f); end; procedure WriteFormat(formatstr: string; params args: array of object); begin var s := Format(formatstr, args); write(s); end; procedure WritelnFormat(formatstr: string; params args: array of object); begin var s := Format(formatstr, args); writeln(s); end; procedure WriteFormat(f: Text; formatstr: string; params args: array of object); begin var s := Format(formatstr, args); write(f, s); end; procedure WritelnFormat(f: Text; formatstr: string; params args: array of object); begin var s := Format(formatstr, args); Writeln(f, s); end; // ----------------------------------------------------- // Print - Println // ----------------------------------------------------- procedure Print(s: string); begin if PrintDelimDefault<>'' then Write(s, PrintDelimDefault) else Write(s) end; procedure Print(o: object); begin if PrintDelimDefault<>'' then Write(o, PrintDelimDefault) else Write(o) end; procedure Print(params args: array of object); begin if args.Length = 0 then exit; for var i := 0 to args.length - 1 do if PrintDelimDefault<>'' then Write(args[i], PrintDelimDefault) else Write(args[i]); end; procedure Println(params args: array of object); begin if args.Length = 0 then begin Writeln; exit; end; for var i := 0 to args.length - 2 do if PrintDelimDefault<>'' then Write(args[i], PrintDelimDefault) else Write(args[i]); Writeln(args[args.Length-1]); end; procedure Print(f: Text; params args: array of object); begin if args.Length = 0 then exit; for var i := 0 to args.length - 1 do if PrintDelimDefault<>'' then Write(f, args[i], PrintDelimDefault) else Write(f, args[i]) end; procedure Println(f: Text; params args: array of object); begin if args.Length = 0 then begin Writeln(f); exit; end; for var i := 0 to args.length - 2 do if PrintDelimDefault<>'' then Write(f, args[i], PrintDelimDefault) else Write(f, args[i]); Writeln(f, args[args.Length-1]); end; procedure Serialize(fileName: string; obj: object); begin var fs := new System.IO.FileStream(filename,System.IO.FileMode.Create); var formatter := new BinaryFormatter; formatter.Serialize(fs,obj); fs.Close; end; function Deserialize(fileName: string): object; begin var fs := new System.IO.FileStream(fileName,System.IO.FileMode.Open); var formatter := new BinaryFormatter; Result := formatter.Deserialize(fs); fs.Close; end; // ----------------------------------------------------- // Text files // ----------------------------------------------------- procedure Assign(f: Text; fileName: string); begin try f.fi := System.IO.FileInfo.Create(fileName); except on e: Exception do raise e; end; if (f = output) or (f = ErrOutput) then f.sw := new StreamWriter(f.fi.FullName); if f = input then begin f.sr := new StreamReader(f.fi.FullName, DefaultEncoding); (CurrentIOSystem as IOStandardSystem).tr := f.sr; (CurrentIOSystem as IOStandardSystem).realbuflen := -1; _IsPipedRedirected := True; _IsPipedRedirectedQuery := True; end; end; procedure AssignFile(f: Text; fileName: string) := Assign(f, fileName); procedure Close(f: Text); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr <> nil then begin f.sr.Close; f.sr := nil; f.sw := nil; // f.fi := nil; end else if f.sw <> nil then begin f.sw.Close; f.sr := nil; f.sw := nil; // f.fi := nil; end else raise new IOException(GetTranslation(FILE_NOT_OPENED)); end; procedure CloseFile(f: Text) := Close(f); procedure Reset(f: Text) := Reset(f, DefaultEncoding); procedure Reset(f: Text; en: Encoding); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sr = nil then begin f.sr := new StreamReader(f.fi.FullName, en); if f.sw <> nil then begin f.sw.Close; f.sw := nil; end; end else begin f.sr.Close; f.sr := new StreamReader(f.fi.FullName, en); //f.sr.BaseStream.Position := 0; //f.sr.DiscardBufferedData; end; if f = input then begin (CurrentIOSystem as IOStandardSystem).tr := f.sr; (CurrentIOSystem as IOStandardSystem).realbuflen := -1; end; end; procedure Reset(f: Text; fileName: string) := Reset(f, fileName, DefaultEncoding); procedure Reset(f: Text; fileName: string; en: Encoding); begin Assign(f, fileName); Reset(f, en); end; procedure Rewrite(f: Text); begin Rewrite(f, DefaultEncoding) end; procedure Rewrite(f: Text; en: Encoding); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.sw = nil then begin f.sw := new StreamWriter(f.fi.FullName, False, en); if f.sr <> nil then begin f.sr.Close; f.sr := nil; end; end else begin if f.sw is StreamWriter then (f.sw as StreamWriter).BaseStream.Position := 0; end; end; procedure Rewrite(f: Text; fileName: string); begin Rewrite(f, fileName, DefaultEncoding) end; procedure Rewrite(f: Text; fileName: string; en: Encoding); begin Assign(f, fileName); Rewrite(f, en); end; procedure Append(f: Text) := Append(f, DefaultEncoding); procedure Append(f: Text; en: Encoding); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); f.sw := new StreamWriter(f.fi.FullName, True, en); end; procedure Append(f: Text; fileName: string) := Append(f, fileName, DefaultEncoding); procedure Append(f: Text; fileName: string; en: Encoding); begin Assign(f, fileName); Append(f, en); end; function OpenRead(fileName: string): Text := OpenRead(fileName, DefaultEncoding); function OpenRead(fileName: string; en: Encoding): Text; begin var f: Text := new Text; Reset(f, fileName, en); Result := f; end; function OpenWrite(fileName: string): Text := OpenWrite(fileName, DefaultEncoding); function OpenWrite(fileName: string; en: Encoding): Text; begin var f: Text := new Text; Rewrite(f, fileName, en); Result := f; end; function OpenAppend(fileName: string): Text := OpenAppend(fileName, DefaultEncoding); function OpenAppend(fileName: string; en: Encoding): Text; begin var f: Text := new Text; Append(f, fileName, en); Result := f; end; function Eof(f: Text): boolean; begin if f = input then Result := Eof else if f.sr <> nil then Result := f.sr.EndOfStream else if f.sw <> nil then raise new IOException(GetTranslation(EOF_FOR_TEXT_WRITEOPENED)) else raise new IOException(GetTranslation(FILE_NOT_OPENED)); end; function Eoln(f: Text): boolean; begin if f = input then Result := Eoln else if f.sr <> nil then Result := f.sr.EndOfStream or (f.sr.Peek = 13) or (f.sr.Peek = 10) else if f.sw <> nil then raise new IOException(GetTranslation(EOLN_FOR_TEXT_WRITEOPENED)) else raise new IOException(GetTranslation(FILE_NOT_OPENED)); end; function SeekEof(f: Text): boolean; begin if f = input then begin Result := SeekEof; exit; end; if f.sw <> nil then raise new IOException(GetTranslation(SEEKEOF_FOR_TEXT_WRITEOPENED)); if f.sr = nil then raise new IOException(GetTranslation(FILE_NOT_OPENED)); repeat if f.sr.EndOfStream then break; var i := f.sr.Peek; if not char.IsWhiteSpace(char(i)) then break; f.sr.Read; until False; Result := f.sr.EndOfStream; end; function SeekEoln(f: Text): boolean; begin if f = input then begin Result := SeekEoln; exit; end; if f.sw <> nil then raise new IOException(GetTranslation(SEEKEOLN_FOR_TEXT_WRITEOPENED)); if f.sr = nil then raise new IOException(GetTranslation(FILE_NOT_OPENED)); repeat if f.sr.EndOfStream then break; var i := f.sr.Peek; // if not char.IsWhiteSpace(char(i)) then if (i <> 32) and (i <> 9) then // Если это не пробел и не табуляция break; f.sr.Read; until False; Result := f.sr.EndOfStream or (f.sr.Peek = 13) or (f.sr.Peek = 10); // Концом строки end; procedure Flush(f: Text); begin if f.sw <> nil then f.sw.Flush end; procedure Erase(f: Text); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); f.fi.Delete; end; procedure Rename(f: Text; newname: string); begin if f.fi = nil then raise new IOException(GetTranslation(FILE_NOT_ASSIGNED)); System.IO.File.Move(f.fi.FullName, newname); end; procedure TextFileInit(var f: Text); begin f := new Text; end; // ----------------------------------------------------- // ReadLines, ReadAllText, WriteLines, WriteAllText // ----------------------------------------------------- function ReadLines(path: string): sequence of string; begin Result := ReadLines(path, DefaultEncoding); end; function ReadLines(path: string; en: Encoding): sequence of string; begin Result := System.IO.File.ReadLines(path, en); end; function ReadAllLines(path: string): array of string; begin Result := ReadAllLines(path, DefaultEncoding); end; function ReadAllLines(path: string; en: Encoding): array of string; begin Result := System.IO.File.ReadAllLines(path, en); end; function ReadAllText(path: string): string; begin Result := ReadAllText(path, DefaultEncoding); end; function ReadAllText(path: string; en: Encoding): string; begin Result := System.IO.File.ReadAllText(path, en); end; procedure WriteLines(path: string; ss: sequence of string); begin WriteLines(path, ss, DefaultEncoding); end; procedure WriteLines(path: string; ss: sequence of string; en: Encoding); begin System.IO.File.WriteAllLines(path, ss, en); end; procedure WriteAllLines(path: string; ss: array of string); begin WriteAllLines(path, ss, DefaultEncoding); end; procedure WriteAllLines(path: string; ss: array of string; en: Encoding); begin System.IO.File.WriteAllLines(path, ss, en); end; procedure WriteAllText(path: string; s: string); begin System.IO.File.WriteAllText(path, s, DefaultEncoding); end; procedure WriteAllText(path: string; s: string; en: Encoding); begin System.IO.File.WriteAllText(path, s, en); end; // ----------------------------------------------------- // Abstract binary files // ----------------------------------------------------- procedure Assign(f: AbstractBinaryFile; fileName: string); begin f.fi := System.IO.FileInfo.Create(fileName); end; procedure AssignFile(f: AbstractBinaryFile; fileName: string) := Assign(f, fileName); procedure Close(f: AbstractBinaryFile); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); if f.fs <> nil then begin f.br.Close; f.bw.Close; f.fs := nil; f.br := nil; f.bw := nil; end; end; procedure CloseFile(f: AbstractBinaryFile) := Close(f); procedure Reset(f: AbstractBinaryFile; en: Encoding); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if (f is TypedFile) and not en.IsSingleByte then raise new System.IO.IOException(GetTranslation(TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY)); if f.fs = nil then begin f.fs := new FileStream(f.fi.FullName, FileMode.Open); f.br := new BinaryReader(f.fs, en); f.bw := new BinaryWriter(f.fs, en); end else f.fs.Position := 0; end; procedure Reset(f: AbstractBinaryFile) := Reset(f,DefaultEncoding); procedure Reset(f: AbstractBinaryFile; fileName: string); begin Assign(f, fileName); Reset(f); end; procedure Reset(f: AbstractBinaryFile; fileName: string; en: Encoding); begin Assign(f, fileName); Reset(f,en); end; procedure Rewrite(f: AbstractBinaryFile; en: Encoding); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if (f is TypedFile) and not en.IsSingleByte then raise new System.IO.IOException(GetTranslation(TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY)); if f.fs = nil then begin f.fs := new FileStream(f.fi.FullName, FileMode.Create); f.bw := new BinaryWriter(f.fs, en); f.br := new BinaryReader(f.fs, en); end else begin f.fs.Position := 0; Truncate(f); end; end; procedure Rewrite(f: AbstractBinaryFile) := Rewrite(f,DefaultEncoding); procedure Rewrite(f: AbstractBinaryFile; fileName: string; en: Encoding); begin Assign(f, fileName); Rewrite(f,en); end; procedure Rewrite(f: AbstractBinaryFile; fileName: string); begin Assign(f, fileName); Rewrite(f); end; procedure Truncate(f: AbstractBinaryFile); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); f.fs.SetLength(f.fs.Position); end; function Eof(f: AbstractBinaryFile): boolean; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); if f.fs <> nil then Result := f.fs.Position = f.fs.Length; end; procedure Erase(f: AbstractBinaryFile); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); f.fi.Delete; end; procedure Rename(f: AbstractBinaryFile; newname: string); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); System.IO.File.Move(f.fi.FullName, newname); end; function AbstractBinaryFileReadT(f: AbstractBinaryFile; t: System.Type; var ind: integer; in_arr: boolean): object; var t1: System.Type; elem: object; fa: array of System.Reflection.FieldInfo; NullBasedArray: System.Array; begin if t.IsPrimitive then begin with f.br do case System.Type.GetTypeCode(t) of TypeCode.Boolean: Result := ReadBoolean; TypeCode.Byte: Result := ReadByte; TypeCode.Char: Result := ReadChar; TypeCode.Decimal: Result := ReadDecimal; TypeCode.Double: Result := ReadDouble; TypeCode.Int16: Result := ReadInt16; TypeCode.Int32: Result := ReadInt32; TypeCode.Int64: Result := ReadInt64; TypeCode.UInt16: Result := ReadUInt16; TypeCode.UInt32: Result := ReadUInt32; TypeCode.UInt64: Result := ReadUInt64; TypeCode.SByte: Result := ReadSByte; TypeCode.Single: Result := ReadSingle; end; end else if t.IsEnum then Result := f.br.ReadInt32 else if t.IsValueType then begin elem := Activator.CreateInstance(t,true); fa := t.GetFields(System.Reflection.BindingFlags.GetField or System.Reflection.BindingFlags.Instance or System.Reflection.BindingFlags.Public or System.Reflection.BindingFlags.NonPublic); for var i := 0 to fa.Length - 1 do if {not fa[i].IsStatic and} not fa[i].IsLiteral then fa[i].SetValue(elem, AbstractBinaryFileReadT(f, fa[i].FieldType, ind, in_arr)); Result := elem; end else if t = typeof(string) then begin if f is TypedFile then begin var len := f.br.ReadByte(); var chh := f.br.ReadChars(len); Result := new string(chh); end else Result := f.br.ReadString(); if (f is TypedFile) and ((f as TypedFile).offsets <> nil) and ((f as TypedFile).offsets.Length > 0) then begin f.br.BaseStream.Seek((f as TypedFile).offsets[ind] - (Result as string).Length, SeekOrigin.Current); end; if not in_arr then Inc(ind); //if f is TypedFile then //f.br.BaseStream.Seek(255-(Result as string).Length,SeekOrigin.Current); end else if t = typeof(TypedSet) then begin Result := f.br.ReadBytes(256 div 8); elem := Activator.CreateInstance(t, Result); Result := elem; end else begin elem := Activator.CreateInstance(t); NullBasedArray := GetNullBasedArray(elem); if NullBasedArray <> nil then begin t1 := NullBasedArray.GetType.GetElementType; var tmp := ind; var tmp2 := 0; for var i := 0 to NullBasedArray.Length - 1 do begin NullBasedArray.SetValue(AbstractBinaryFileReadT(f, t1, ind, i = 0 ? false : true), i); if i = 0 then tmp2 := ind; ind := tmp; end; ind := tmp2; end; result := elem; end; end; procedure Write(f: AbstractBinaryFile; val: object; arr: boolean; var ind: integer; in_arr: boolean); var t: System.Type; fa: array of System.Reflection.FieldInfo; NullBasedArray: System.Array; begin t := val.GetType; if f is TypedFile and not arr then begin t := (f as TypedFile).ElementType; end; if t.IsPrimitive or t.IsEnum then begin if t = typeof(integer) then f.bw.Write(Convert.ToInt32(val)) else if t = typeof(real) then f.bw.Write(Convert.ToDouble(val)) else if t = typeof(char) then f.bw.Write(Convert.ToChar(val)) else if t = typeof(boolean) then f.bw.Write(Convert.ToBoolean(val)) else if t = typeof(byte) then f.bw.Write(Convert.ToByte(val)) else if t = typeof(shortint) then f.bw.Write(Convert.ToSByte(val)) else if t = typeof(smallint) then f.bw.Write(Convert.ToInt16(val)) else if t = typeof(word) then f.bw.Write(Convert.ToUInt16(val)) else if t = typeof(longword) then f.bw.Write(Convert.ToUInt32(val)) else if t = typeof(int64) then f.bw.Write(Convert.ToInt64(val)) else if t = typeof(uint64) then f.bw.Write(Convert.ToUInt64(val)) else if t = typeof(single) then f.bw.Write(Convert.ToSingle(val)) else if t.IsEnum then f.bw.Write(Convert.ToInt32(val)); end else if t.IsValueType then begin fa := t.GetFields(System.Reflection.BindingFlags.GetField or System.Reflection.BindingFlags.Instance or System.Reflection.BindingFlags.Public or System.Reflection.BindingFlags.NonPublic); for var i := 0 to fa.Length - 1 do begin if {not fa[i].IsStatic and} not fa[i].IsLiteral then Write(f, fa[i].GetValue(val), true, ind, in_arr); end; end else if t = typeof(string) then begin //var tmp := f.bw.BaseStream.Position; if f is TypedFile then begin f.bw.Write(byte(string(val).Length)); f.bw.Write(string(val).ToArray); end else f.bw.Write(string(val)); if (f is TypedFile) and ((f as TypedFile).offsets <> nil) and ((f as TypedFile).offsets.Length > 0) then begin f.bw.Write(new byte[(f as TypedFile).offsets[ind] - (val as string).Length]); end; if not in_arr then Inc(ind); end else if t = typeof(TypedSet) then begin f.bw.Write((val as TypedSet).GetBytes()); end else begin NullBasedArray := GetNullBasedArray(val); if NullBasedArray <> nil then begin var tmp := ind; var tmp2 := 0; for var i := 0 to NullBasedArray.Length - 1 do begin Write(f, NullBasedArray.GetValue(i), true, ind, i = 0 ? false : true); if i = 0 then tmp2 := ind; ind := tmp; end; ind := tmp2; end; end; end; procedure Write(f: AbstractBinaryFile; params vals: array of object); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); for var i := 0 to vals.Length - 1 do begin var NullBasedArray := GetNullBasedArray(vals[i]); var ind := 0; Write(f, vals[i], NullBasedArray <> nil, ind, false); end; end; procedure Writeln(f: AbstractBinaryFile); begin raise new System.IO.IOException(GetTranslation(WRITELN_IN_BINARYFILE_ERROR_MESSAGE)); end; procedure Writeln(f: AbstractBinaryFile; val: object); begin raise new System.IO.IOException(GetTranslation(WRITELN_IN_BINARYFILE_ERROR_MESSAGE)); end; procedure Writeln(f: AbstractBinaryFile; params vals: array of object); begin raise new System.IO.IOException(GetTranslation(WRITELN_IN_BINARYFILE_ERROR_MESSAGE)); end; // ----------------------------------------------------- // Typed files // ----------------------------------------------------- function FilePos(f: TypedFile): int64; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); Result := f.fs.Position div f.ElementSize; end; function FileSize(f: TypedFile): int64; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); if f.fs.Length mod f.ElementSize <> 0 then raise new System.IO.IOException('Bad typed file size'); Result := f.fs.Length div f.ElementSize; end; procedure Seek(f: TypedFile; n: int64); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); f.fs.Position := n * f.ElementSize end; procedure TypedFileInit(var f: TypedFile; ElementType: System.Type); begin f := new TypedFile(ElementType, 0, new integer[0]); end; procedure TypedFileInit(var f: TypedFile; ElementType: System.Type; off: integer; params offs: array of integer); begin f := new TypedFile(ElementType, off, offs); end; procedure TypedFileInitWithShortString(var f: TypedFile; ElementType: System.Type; off: integer; params offs: array of integer); begin f := new TypedFile(ElementType, off, offs); end; function TypedFileRead(f: TypedFile): object; begin var ind := 0; if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); Result := AbstractBinaryFileReadT(f, f.ElementType, ind, false); //if f.offset > 0 then //f.fs.Seek(tmp+(f as TypedFile).ElementSize-f.fs.Position,SeekOrigin.Current); end; // ----------------------------------------------------- // Binary files // ----------------------------------------------------- function FilePos(f: BinaryFile): int64; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); Result := f.fs.Position; end; function FileSize(f: BinaryFile): int64; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); Result := f.fs.Length; end; procedure Seek(f: BinaryFile; n: int64); begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); f.fs.Position := n; end; procedure BinaryFileInit(var f: BinaryFile); begin f := new BinaryFile(); end; function BinaryFileRead(var f: BinaryFile; ElementType: System.Type): object; begin if f.fi = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_ASSIGNED)); if f.fs = nil then raise new System.IO.IOException(GetTranslation(FILE_NOT_OPENED)); var ind := 0; Result := AbstractBinaryFileReadT(f, ElementType, ind, false); end; // ----------------------------------------------------- // Operating System subroutines: implementation // ----------------------------------------------------- function PascalABCVersion: string; begin Result := '3.2.0.1364'{PABC_VERSION}; end; function ParamCount: integer; begin if (Environment.GetCommandLineArgs.Length > 1) and ((Environment.GetCommandLineArgs[1] = '[REDIRECTIOMODE]') or (Environment.GetCommandLineArgs[1] = '[RUNMODE]')) then Result := Environment.GetCommandLineArgs.Length - 2 else Result := Environment.GetCommandLineArgs.Length - 1; end; function ParamStr(i: integer): string; begin if (Environment.GetCommandLineArgs.Length > 1) and ((Environment.GetCommandLineArgs[1] = '[REDIRECTIOMODE]') or (Environment.GetCommandLineArgs[1] = '[RUNMODE]')) then Result := Environment.GetCommandLineArgs[i + 1] else Result := Environment.GetCommandLineArgs[i]; end; function GetDir: string; begin Result := Environment.CurrentDirectory; end; procedure ChDir(dirName: string); begin Environment.CurrentDirectory := dirName; end; procedure MkDir(dirName: string); begin Directory.CreateDirectory(dirName); end; procedure RmDir(dirName: string); begin Directory.Delete(dirName); end; function CreateDir(dirName: string): boolean; begin try Result := True; Directory.CreateDirectory(dirName); except Result := False; end; end; function DeleteFile(fileName: string): boolean; begin if not &File.Exists(fileName) then begin Result := False; exit end; try Result := True; &File.Delete(fileName); except Result := False; end; end; function GetCurrentDir: string; begin Result := Environment.CurrentDirectory; end; function RemoveDir(dirName: string): boolean; begin try Result := True; Directory.Delete(dirName); except Result := False; end; end; function RenameFile(fileName, newfileName: string): boolean; begin try Result := True; &File.Move(fileName, newfileName); except Result := False; end; end; function RenameDirectory(dirName, newDirName: string): boolean; begin try Result := True; Directory.Move(dirName, newDirName); except Result := False; end; end; function SetCurrentDir(dirName: string): boolean; begin try Result := True; Environment.CurrentDirectory := dirName; except Result := False; end; end; function ChangeFileNameExtension(fileName, newext: string): string; begin Result := System.IO.Path.ChangeExtension(fileName, newext); end; function FileExists(fileName: string): boolean; begin Result := System.IO.File.Exists(fileName); end; [System.Diagnostics.Conditional('DEBUG')] procedure Assert(cond: boolean; sourceFile: string; line: integer); begin if (Environment.OSVersion.Platform = PlatformID.Unix) or (Environment.OSVersion.Platform = PlatformID.MacOSX) or IsWDE then begin //var stackTrace := new System.Diagnostics.StackTrace(true); //var ind := 1; //if stackTrace.GetFrame(0).GetMethod().Name <> 'Assert' then //ind := 0; //var currentLine := stackTrace.GetFrame(ind).GetFileLineNumber(); //var currentFile := stackTrace.GetFrame(ind).GetFileName(); if not IsWDE then System.Diagnostics.Debug.Assert(cond, 'Файл ' + sourceFile + ', строка ' + line.ToString()) else if not cond then begin var err := 'Сбой подтверждения: ' + Environment.NewLine + 'Файл ' + sourceFile + ', строка ' + line.ToString(); writeln(err); System.Threading.Thread.Sleep(500); raise new Exception(); end; end else //System.Diagnostics.Debug.Assert(cond); System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString()) end; [System.Diagnostics.Conditional('DEBUG')] procedure Assert(cond: boolean; message: string; sourceFile: string; line: integer); begin if (Environment.OSVersion.Platform = PlatformID.Unix) or (Environment.OSVersion.Platform = PlatformID.MacOSX) or IsWDE then begin //var stackTrace := new System.Diagnostics.StackTrace(true); //var ind := 1; //if stackTrace.GetFrame(0).GetMethod().Name <> 'Assert' then // ind := 0; //var currentLine := stackTrace.GetFrame(ind).GetFileLineNumber(); //var currentFile := stackTrace.GetFrame(ind).GetFileName(); if not IsWDE then System.Diagnostics.Debug.Assert(cond, 'Файл ' + sourceFile + ', строка ' + line.ToString() + ': ' + message) else if not cond then begin var err := 'Сбой подтверждения: ' + message + Environment.NewLine + 'Файл ' + sourceFile + ', строка ' + line.ToString(); Writeln(err); System.Threading.Thread.Sleep(500); raise new Exception(); end; end else //System.Diagnostics.Debug.Assert(cond, message); System.Diagnostics.Contracts.Contract.Assert(cond,'Файл '+sourceFile+', строка '+line.ToString() + ': ' + message) end; function DiskFree(diskName: string): int64; begin try var d := new System.IO.DriveInfo(diskname); Result := d.TotalFreeSpace; except Result := -1; end; end; function DiskSize(diskName: string): int64; begin try var d := new System.IO.DriveInfo(diskname); Result := d.TotalSize; except Result := -1; end; end; function ConvertDiskToDiskName(disk: integer): string; begin if disk = 0 then begin var s := Paramstr(0); var p := Pos(':', s); if p > 0 then Result := Copy(s, 1, p) else Result := 'C:'; end else begin if disk < 0 then disk := 0; if disk > 26 then disk := 26; var ch := 'A'; Inc(ch, disk - 1); Result := ch + ':'; end; end; function DiskFree(disk: integer): int64; begin Result := DiskFree(ConvertDiskToDiskName(disk)); end; function DiskSize(disk: integer): int64; begin Result := DiskSize(ConvertDiskToDiskName(disk)); end; var curr_time := DateTime.Now; function Milliseconds: integer; begin curr_time := DateTime.Now; Milliseconds := Convert.ToInt32((curr_time - StartTime).TotalMilliseconds); end; function MillisecondsDelta: integer; begin var t := DateTime.Now; Result := Convert.ToInt32((t - curr_time).TotalMilliseconds); curr_time := DateTime.Now; end; procedure Halt; begin System.Diagnostics.Process.GetCurrentProcess.Kill; //Halt(ExitCode); end; procedure Halt(exitCode: integer); begin //System.Diagnostics.Process.GetCurrentProcess.Kill; //WINAPI_TerminateProcess(System.Diagnostics.Process.GetCurrentProcess.Handle, exitCode); System.Environment.Exit(exitCode); end; procedure Sleep(ms: integer); begin System.Threading.Thread.Sleep(ms); end; function GetEXEFileName: string; begin Result := System.Reflection.Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName; end; function PointerToString(p: pointer): string; begin //result:= Convert.ToString(integer(p), 16); if p = nil then result := 'nil' else if Environment.Is64BitProcess then result := '$' + int64(p).ToString('X') else result := '$' + integer(p).ToString('X') end; procedure Exec(fileName: string); begin System.Diagnostics.Process.Start(fileName) end; procedure Exec(fileName: string; args: string); begin System.Diagnostics.Process.Start(fileName, args) end; procedure Execute(fileName: string); begin System.Diagnostics.Process.Start(fileName) end; procedure Execute(fileName: string; args: string) := System.Diagnostics.Process.Start(fileName, args); // ----------------------------------------------------- // EnumerateFiles, EnumerateDirectories // ----------------------------------------------------- function EnumerateFiles(path: string; searchPattern: string): sequence of string; begin Result := System.IO.Directory.EnumerateFiles(path, searchPattern, System.IO.SearchOption.TopDirectoryOnly) end; function EnumerateAllFiles(path: string; searchPattern: string): sequence of string; begin Result := System.IO.Directory.EnumerateFiles(path, searchPattern, System.IO.SearchOption.AllDirectories) end; function EnumerateDirectories(path: string): sequence of string; begin Result := System.IO.Directory.EnumerateDirectories(path, '*.*', System.IO.SearchOption.TopDirectoryOnly) end; function EnumerateAllDirectories(path: string): sequence of string; begin Result := System.IO.Directory.EnumerateDirectories(path, '*.*', System.IO.SearchOption.AllDirectories) end; // ----------------------------------------------------- // File name functions: implementation // ----------------------------------------------------- function ExtractFileName(fileName: string): string; begin var fi := new System.IO.FileInfo(fileName); Result := fi.Name; end; function ExtractFileExt(fileName: string): string; begin var fi := new System.IO.FileInfo(fileName); Result := fi.Extension; end; function ExtractFilePath(fileName: string): string; begin var fi := new System.IO.FileInfo(fileName); Result := fi.DirectoryName; if (Result.Length > 0) and (Result[Result.Length] <> '\') and (Result[Result.Length] <> '/') then Result += '\'; end; function ExtractFileDir(fileName: string): string; begin var fi := new System.IO.FileInfo(fileName); Result := fi.DirectoryName; end; function ExtractFileDrive(fileName: string): string; begin try var fi := new System.IO.FileInfo(fileName); Result := fi.DirectoryName; var p := Pos(':', Result); if p > 0 then Result := Copy(Result, 1, p) else Result := ''; except on e: Exception do raise e; end; end; function ExpandFileName(fileName: string): string; begin var fi := new System.IO.FileInfo(fileName); Result := fi.FullName; end; // ----------------------------------------------------- // Mathematical functions: implementation // ----------------------------------------------------- function Sign(x: shortint): integer := Math.Sign(x); function Sign(x: smallint): integer := Math.Sign(x); function Sign(x: integer): integer := Math.Sign(x); function Sign(x: BigInteger) := x.Sign; function Sign(x: int64) := Math.Sign(x); function Sign(x: byte): integer := 1; function Sign(x: word): integer := 1; function Sign(x: longword): integer := 1; function Sign(x: uint64): integer := 1; function Sign(x: real): integer := Math.Sign(x); function Abs(x: shortint): shortint := if x >= 0 then x else -x; function Abs(x: smallint): smallint := if x >= 0 then x else -x; function Abs(x: integer): integer := if x >= 0 then x else -x; function Abs(x: int64): int64 := if x >= 0 then x else -x; function Abs(x: BigInteger): BigInteger := BigInteger.Abs(x); function Abs(x: byte): byte := x; function Abs(x: word): word := x; function Abs(x: longword): longword := x; function Abs(x: uint64): uint64 := x; function Abs(x: real): real := Math.Abs(x); function Abs(x: single): single := Math.Abs(x); function Sin(x: real) := Math.Sin(x); function Sinh(x: real) := Math.Sinh(x); function Cos(x: real) := Math.Cos(x); function Cosh(x: real) := Math.Cosh(x); function Tan(x: real) := Math.Tan(x); function Tanh(x: real) := Math.Tanh(x); function ArcSin(x: real) := Math.Asin(x); function ArcCos(x: real) := Math.Acos(x); function ArcTan(x: real) := Math.Atan(x); function Exp(x: real) := Math.Exp(x); function Ln(x: real) := Math.Log(x); function Log(x: real) := Math.Log(x); function Log2(x: real) := LogN(2, x); function Log10(x: real) := Math.Log10(x); function LogN(base, x: real) := Math.Log(x) / Math.Log(base); function Sqrt(x: real) := Math.Sqrt(x); function Sqr(x: integer): int64 := int64(x) * int64(x); function Sqr(x: shortint): integer := x * x; function Sqr(x: smallint): integer := x * x; function Sqr(x: BigInteger): BigInteger := x * x; function Sqr(x: byte): integer := x * x; function Sqr(x: word): uint64 := uint64(x) * uint64(x); function Sqr(x: longword): uint64 := uint64(x) * uint64(x); function Sqr(x: int64): int64 := int64(x) * int64(x); function Sqr(x: uint64): uint64 := x * x; function Sqr(x: real): real := x * x; function Power(x, y: real): real := Math.Pow(x, y); //function Power(x, y: integer): real := Math.Pow(x, y); function Power(x: real; n: integer): real; begin case n of 0: Result := 1; 1: Result := x; 2: Result := x*x; 3: Result := x*x*x; 4: Result := x*x*x*x; 5: Result := x*x*x*x*x; 6: Result := x*x*x*x*x*x; else if n<0 then Result := 1/Power(x,-n) else begin var z := x; var r := 1.0; while n > 0 do begin if n and 1 = 1 then r := r * z; z := z * z; n := n shr 1; end; Result := r; end; end; end; function Power(x: BigInteger; y: integer) := BigInteger.Pow(x, y); function Round(x: real) := Convert.ToInt32(x); function Round(x: real; digits: integer) := Math.Round(x,digits); function RoundBigInteger(x: real) := BigInteger.Create(Math.Round(x)); function Trunc(x: real) := Convert.ToInt32(Math.Truncate(x)); function TruncBigInteger(x: real) := BigInteger.Create(Math.Truncate(x)); function Int(x: real) := x >= 0 ? Math.Floor(x) : Math.Ceiling(x); function Frac(x: real) := x - Int(x); function Floor(x: real) := Convert.ToInt32(Math.Floor(x)); function Ceil(x: real) := Convert.ToInt32(Math.Ceiling(x)); function RadToDeg(x: real) := x * 180 / Pi; function DegToRad(x: real) := x * Pi / 180; procedure Randomize; begin rnd := new System.Random; end; procedure Randomize(seed: integer); begin rnd := new System.Random(seed); end; function Random(MaxValue: integer) := rnd.Next(MaxValue); function Random(a, b: integer): integer; begin if a > b then Swap(a, b); Result := rnd.Next(a, b + 1); end; function Random(a, b: char) := Chr(Random(integer(a), integer(b))); function Random(a, b: real): real; begin if a > b then Swap(a, b); Result := a + Random()*(b-a); end; function RandomReal(a, b: real; digits: integer): real; begin if digits<0 then Result := Random(a,b) else begin // Бывают некорректные данные. Например, найти точку с 2 знаками на [2.736, 2.737]. Тогда возвращать a скажем var step := 1/10**digits; Result := Round(Random(a,b),digits); if Result < a then begin Result += step; if Result > b then Result := b end else if Result > b then begin Result -= step; if Result < a then Result := a; end; end; end; function Random(diap: IntRange): integer := Random(diap.Low,diap.High); function Random(diap: RealRange): real := Random(diap.Low,diap.High); function Random(diap: CharRange): char := Random(diap.Low,diap.High); function Random := rnd.NextDouble; function Random(MaxValue: real) := Random()*Abs(MaxValue); function Random2(maxValue: integer) := (Random(maxValue), Random(maxValue)); function Random2(maxValue: real) := (Random(maxValue), Random(maxValue)); function Random2(a, b: integer) := (Random(a, b), Random(a, b)); function Random2(a, b: char) := (Random(a, b), Random(a, b)); function Random2(a, b: real) := (Random(a, b), Random(a, b)); function Random2(diap: IntRange) := Random2(diap.Low,diap.High); function Random2(diap: RealRange) := Random2(diap.Low,diap.High); function Random2(diap: CharRange) := Random2(diap.Low,diap.High); function Random2 := (Random, Random); function Random3(maxValue: integer) := (Random(maxValue), Random(maxValue), Random(maxValue)); function Random3(maxValue: Real) := (Random(maxValue), Random(maxValue), Random(maxValue)); function Random3(a, b: integer) := (Random(a, b), Random(a, b), Random(a, b)); function Random3(a, b: char) := (Random(a, b), Random(a, b), Random(a, b)); function Random3(a, b: real) := (Random(a, b), Random(a, b), Random(a, b)); function Random3(diap: IntRange) := Random3(diap.Low,diap.High); function Random3(diap: RealRange) := Random3(diap.Low,diap.High); function Random3(diap: CharRange) := Random3(diap.Low,diap.High); function Random3 := (Random, Random, Random); function Max(a, b: byte) := Math.Max(a, b); function Max(a, b: shortint) := Math.Max(a, b); function Max(a, b: word) := Math.Max(a, b); function Max(a, b: smallint) := Math.Max(a, b); function Max(a, b: integer) := Math.Max(a, b); function Max(a, b: BigInteger) := BigInteger.Max(a, b); function Max(a, b: longword) := Math.Max(a, b); function Max(a, b: int64) := Math.Max(a, b); function Max(a, b: uint64) := Math.Max(a, b); function Max(a, b: real) := Math.Max(a, b); function Max(a, b, c: integer): integer; begin Result := a; if b > Result then Result := b; if c > Result then Result := c; end; function Max(a, b, c, d: integer): integer; begin Result := a; if b > Result then Result := b; if c > Result then Result := c; if d > Result then Result := d; end; function Max(a, b, c: real): real; begin Result := a; if b > Result then Result := b; if c > Result then Result := c; end; function Max(a, b, c, d: real): real; begin Result := a; if b > Result then Result := b; if c > Result then Result := c; if d > Result then Result := d; end; //function Max(params a: array of integer): integer := a.Max; //function Max(params a: array of real): real := a.Max; function Min(a, b: byte) := Math.Min(a, b); function Min(a, b: shortint) := Math.Min(a, b); function Min(a, b: word) := Math.Min(a, b); function Min(a, b: smallint) := Math.Min(a, b); function Min(a, b: integer) := Math.Min(a, b); function Min(a, b: BigInteger) := BigInteger.Min(a, b); function Min(a, b: longword) := Math.Min(a, b); function Min(a, b: int64) := Math.Min(a, b); function Min(a, b: uint64) := Math.Min(a, b); function Min(a, b: real) := Math.Min(a, b); function Min(a, b, c: integer): integer; begin Result := a; if b < Result then Result := b; if c < Result then Result := c; end; function Min(a, b, c, d: integer): integer; begin Result := a; if b < Result then Result := b; if c < Result then Result := c; if d < Result then Result := d; end; function Min(a, b, c: real): real; begin Result := a; if b < Result then Result := b; if c < Result then Result := c; end; function Min(a, b, c, d: real): real; begin Result := a; if b < Result then Result := b; if c < Result then Result := c; if d < Result then Result := d; end; function Min(params a: array of T): T; begin if a.Length<2 then raise new System.ArgumentException(GetTranslation(COUNT_PARAMS_MINFUN_MUSTBE_GREATER1)); Result := a.Min; end; function Max(params a: array of T): T; begin if a.Length<2 then raise new System.ArgumentException(GetTranslation(COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1)); Result := a.Max; end; {function Min(params a: array of real): real := a.Min;} function Odd(i: byte) := (i mod 2) <> 0; function Odd(i: shortint) := (i mod 2) <> 0; function Odd(i: word) := (i mod 2) <> 0; function Odd(i: smallint) := (i mod 2) <> 0; function Odd(i: integer) := (i mod 2) <> 0; function Odd(i: BigInteger) := not i.IsEven; function Odd(i: longword) := (i mod 2) <> 0; function Odd(i: int64) := (i mod 2) <> 0; function Odd(i: uint64) := (i mod 2) <> 0; function Cplx(re, im: real) := new Complex(re, im); function CplxFromPolar(magnitude, phase: real) := Complex.FromPolarCoordinates(magnitude, phase); function Sqrt(c: Complex) := Complex.Sqrt(c); function Abs(c: Complex) := Complex.Abs(c); function Conjugate(c: Complex) := Complex.Conjugate(c); function Cos(c: Complex) := Complex.Cos(c); function Exp(c: Complex) := Complex.Exp(c); function Log(c: Complex) := Complex.Log(c); function Ln(c: Complex) := Complex.Log(c); function Log10(c: Complex) := Complex.Log10(c); function Power(c, power: Complex) := Complex.Pow(c, power); function Sin(c: Complex) := Complex.Sin(c); // ----------------------------------------------------- // Dynamic arrays: implementation // ----------------------------------------------------- function Low(i: System.Array): integer; begin if i <> nil then Result := i.GetLowerBound(0) else Result := 0; end; function High(i: System.Array): integer; begin if i <> nil then Result := i.GetUpperBound(0) else Result := -1; end; function Length(a: &Array): integer; begin if a = nil then Result := 0 else Result := a.Length; end; function Length(a: &Array; dim: integer): integer; begin if a = nil then Result := 0 else Result := a.GetLength(dim); end; function Copy(a: &Array): &Array; begin Result := &Array(a.Clone()); end; procedure Sort(a: array of T); begin System.Array.Sort(a); end; procedure Sort(a: array of string); begin System.Array.Sort(a, System.StringComparer.Ordinal); end; procedure Sort(a: array of T; cmp: (T,T)->integer); begin System.Array.Sort(a, cmp); end; procedure Sort(a: array of T; less: (T,T)->boolean); begin System.Array.Sort(a, (x, y)-> less(x, y) ? -1 : (less(y, x) ? 1 : 0)); end; procedure Sort(a: array of T; keySelector: T->TKey); begin var keys := System.Array.ConvertAll(a,keySelector); System.Array.Sort(keys, a); end; procedure Sort(a: array of T; keySelector: T->string); begin var keys := System.Array.ConvertAll(a,keySelector); System.Array.Sort(keys, a, System.StringComparer.Ordinal); end; procedure Sort(l: List); begin l.Sort(); end; procedure Sort(var l: List); begin l := l.OrderBy(x->x, System.StringComparer.Ordinal).ToList; end; procedure Sort(var l: List; keySelector: T->T1); begin l := l.OrderBy(x->keySelector(x)).ToList; end; procedure Sort(var l: List; keySelector: T->string); begin l := l.OrderBy(x->keySelector(x),System.StringComparer.Ordinal).ToList; end; procedure Sort(l: List; cmp: (T,T)->integer); begin l.Sort(cmp); end; procedure Sort(l: List; less: (T,T)->boolean); begin l.Sort((x, y)-> less(x, y) ? -1 : (less(y, x) ? 1 : 0)); end; procedure SortDescending(a: array of T); begin Sort(a); Reverse(a); end; procedure SortDescending(a: array of string); begin Sort(a); Reverse(a); end; procedure SortDescending(var a: array of T; keySelector: T->T1); begin a := a.OrderByDescending(x->keySelector(x)).ToArray; end; procedure SortDescending(var a: array of T; keySelector: T->string); begin a := a.OrderByDescending(x->keySelector(x),System.StringComparer.Ordinal).ToArray; end; procedure SortDescending(l: List); begin Sort(l); Reverse(l); end; procedure SortDescending(var l: List); begin l := l.OrderByDescending(x->x, System.StringComparer.Ordinal).ToList; end; procedure SortDescending(var l: List; keySelector: T->T1); begin l := l.OrderByDescending(x->keySelector(x)).ToList; end; procedure SortDescending(var l: List; keySelector: T->string); begin l := l.OrderByDescending(x->keySelector(x), System.StringComparer.Ordinal).ToList; end; procedure Reverse(a: array of T); begin System.Array.Reverse(a); end; procedure Reverse(a: array of T; index, count: integer); begin System.Array.Reverse(a, index, count); end; procedure Reverse(a: List); begin a.Reverse end; procedure Reverse(a: List; index, count: integer); begin a.Reverse(index, count) end; procedure Reverse(var s: string); begin var cc := s.ToCharArray; Reverse(cc); s := new string(cc); end; procedure Reverse(var s: string; index, count: integer); begin var cc := s.ToCharArray; Reverse(cc,index-1,count); s := new string(cc); end; procedure Shuffle(a: array of T); begin for var i := a.Length - 1 downto 1 do Swap(a[i], a[Random(i + 1)]); end; procedure Shuffle(l: List); begin for var i := l.Count - 1 downto 1 do begin var ind := Random(i + 1); var v := l[i]; l[i] := l[ind]; l[ind] := v; end; end; // ----------------------------------------------------- // Char and String: implementation // ----------------------------------------------------- function ChrAnsi(a: Byte): char; begin if a < 128 then Result := char(a) else begin //__one_byte[0] := a; Result := Encoding.GetEncoding(1251).GetChars(new byte[1](a))[0]; end; end; function OrdAnsi(a: char): byte; begin if a < #128 then Result := byte(a) else begin //__one_char[0] := a; Result := Encoding.GetEncoding(1251).GetBytes(new char[1](a))[0]; end; end; function Ord(a: integer): integer; begin Result := a; end; function Ord(a: longword): longword; begin Result := a; end; function Ord(a: int64): int64; begin Result := a; end; function Ord(a: uint64): uint64; begin Result := a; end; function Ord(a: boolean): integer; begin Result := integer(a); end; function Ord(a: char): word; begin Result := word(a); end; function Chr(a: word): char; begin Result := Convert.ToChar(a); end; function ChrUnicode(a: word): char; begin Result := Convert.ToChar(a); end; function OrdUnicode(a: char): word; begin Result := word(a); end; function UpperCase(ch: char): char; begin Result := char.ToUpper(ch); end; function LowerCase(ch: char): char; begin Result := char.ToLower(ch); end; function UpCase(ch: char): char; begin Result := char.ToUpper(ch); end; function LowCase(ch: char): char; begin Result := char.ToLower(ch); end; procedure Str(i: integer; var s: string); begin s := i.ToString; end; procedure Str(i: longword; var s: string); begin s := i.ToString; end; procedure Str(i: int64; var s: string); begin s := i.ToString; end; procedure Str(i: uint64; var s: string); begin s := i.ToString; end; procedure Str(s1: string; var s: string); begin s := s1; end; procedure Str(r: single; var s: string); begin s := Convert.ToString(r, nfi); end; procedure Str(r: real; var s: string); begin s := Convert.ToString(r, nfi); end; function Pos(subs, s: string; from: integer): integer; begin if (subs = nil) or (subs.Length = 0) or (from > s.Length) then Result := 0 else Result := s.IndexOf(subs, from - 1, System.StringComparison.Ordinal) + 1; end; function PosEx(subs, s: string; from: integer) := Pos(subs,s,from); function LastPos(subs, s: string): integer; begin if (subs = nil) or (subs.Length = 0) then Result := 0 else Result := s.LastIndexOf(subs, s.Length - 1, System.StringComparison.Ordinal) + 1; end; function LastPos(subs, s: string; from: integer): integer; begin if (subs = nil) or (subs.Length = 0) or (from > s.Length) then Result := 0 else Result := s.LastIndexOf(subs, from - 1, System.StringComparison.Ordinal) + 1; end; {function Pos(c: char; s: string; from: integer): integer; begin if from > s.Length then Result := 0; Result := s.IndexOf(c, from - 1, System.StringComparison.Ordinal) + 1; end; function PosEx(c: char; s: string; from: integer) := Pos(c,s,from); function LastPos(c: char; s: string): integer; begin Result := s.LastIndexOf(c, s.Length - 1, System.StringComparison.Ordinal) + 1; end; function LastPos(c: char; s: string; from: integer): integer; begin if from > s.Length then Result := 0; Result := s.LastIndexOf(c, from - 1, System.StringComparison.Ordinal) + 1; end;} function Length(s: string): integer; begin if s <> nil then Result := s.Length else Result := 0; end; procedure SetLength(var s: string; n: integer); begin if n < 0 then raise new System.ArgumentOutOfRangeException('n'); if n = 0 then s := String.Empty else if s.Length > n then s := s.Substring(0, n) else if s.Length < n then s += new string(' ', n - s.Length); end; procedure SetLengthForShortString(var s: string; n, sz: integer); begin if n < 0 then raise new System.ArgumentOutOfRangeException('n'); if n = 0 then s := String.Empty else if s.Length > n then s := s.Substring(0, n) else if s.Length < n then if n <= sz then s += new string(' ', n - s.Length) else s += new String(' ', sz - s.Length) end; procedure Insert(subs: string; var s: string; index: integer); // Insert никогда не возвращает исключения begin if index < 1 then index := 1; if index > s.Length + 1 then index := s.Length + 1; s := s.Insert(index - 1, subs); end; procedure InsertInShortString(subs: string; var s: string; index, n: integer); begin if index < 1 then index := 1; if index > n then exit; try s := s.Insert(index - 1, subs); if s.Length > n then s := s.Substring(0, n); except s := s.Insert(s.Length, subs); if s.Length > n then s := s.Substring(0, n); end; end; procedure Delete(var s: string; index, count: integer); // Delete никогда не возвращает исключения begin if (index < 1) or (index > s.Length) or (count <= 0) then Exit; if index + count - 1 > s.Length then count := s.Length - index + 1; s := s.Remove(index - 1, count); end; function Copy(s: string; index, count: integer): string; // Copy никогда не возвращает исключения begin if index < 1 then index := 1; if (index > s.Length) or (count <= 0) then begin Result := ''; exit; end; if index + count - 1 > s.Length then count := s.Length - index + 1; Result := s.SubString(index - 1, count); end; function Concat(s1, s2: string): string; begin Result := s1 + s2; end; function Concat(params strs: array of string): string; begin var sb := new System.Text.StringBuilder; for var i := 0 to strs.length - 1 do sb.Append(strs[i]); concat := sb.ToString; end; function LowerCase(s: string): string; begin Result := s.ToLower; end; function UpperCase(s: string): string; begin Result := s.ToUpper; end; function StringOfChar(ch: char; count: integer): string; begin Result := new string(ch, count); end; function ReverseString(s: string): string; begin var ca := s.ToCharArray; &Array.Reverse(ca); Result := new string(ca); end; function ReverseString(s: string; index,length: integer): string; begin var ca := s.ToCharArray; &Array.Reverse(ca,index-1,length); Result := new string(ca); end; function CompareStr(s1, s2: string): Integer; begin Result := string.CompareOrdinal(s1, s2); end; function LeftStr(s: string; count: integer): string; begin if count > s.Length then count := s.Length; Result := s.Substring(0, count) end; function RightStr(s: string; count: integer): string; begin if count > s.Length then count := s.Length; Result := s.Substring(s.Length - count, count); end; function Trim(s: string): string; begin Result := s.Trim(|' '|); end; function TrimLeft(s: string): string; begin Result := s.TrimStart(' '); end; function TrimRight(s: string): string; begin Result := s.TrimEnd(' '); end; function StrToInt(s: string): integer; begin var j := 1; while (j <= s.Length) and char.IsWhiteSpace(s[j]) do j += 1; if (j > s.Length) then raise new System.FormatException(GetTranslation(Format_InvalidString)); var sign := 0; if s[j] = '-' then begin sign := -1; j += 1; end else if s[j] = '+' then begin sign := 1; j += 1; end; if (j > s.Length) then raise new System.FormatException(GetTranslation(Format_InvalidString)); var c := integer(s[j]); if (c < 48) or (c > 57) then raise new System.FormatException(GetTranslation(Format_InvalidString)); Result := c - 48; j += 1; while j <= s.Length do begin c := integer(s[j]); if c > 57 then break; if c < 48 then break; if Result > 214748364 then raise new System.OverflowException(GetTranslation(Overflow_Int32)); Result := Result * 10 + (c - 48); j += 1; end; if Result < 0 then if (Result = -2147483648) and (sign = -1) then exit else raise new System.OverflowException(GetTranslation(Overflow_Int32)); if sign = -1 then Result := -Result; while (j <= s.Length) and char.IsWhiteSpace(s[j]) do j += 1; if j <= s.Length then raise new System.FormatException(GetTranslation(Format_InvalidString)); end; function TryStrToInt(s: string; var value: integer): boolean; begin Result := True; var Res := 0; var j := 1; while (j <= s.Length) and char.IsWhiteSpace(s[j]) do j += 1; if (j > s.Length) then begin Result := False; exit end; var sign := 0; if s[j] = '-' then begin sign := -1; j += 1; end else if s[j] = '+' then begin sign := 1; j += 1; end; if (j > s.Length) then begin Result := False; exit end; var c := integer(s[j]); if (c < 48) or (c > 57) then begin Result := False; exit end; Res := c - 48; j += 1; while j <= s.Length do begin c := integer(s[j]); if c > 57 then break; if c < 48 then break; if Res > 214748364 then begin Result := False; exit end; Res := Res * 10 + (c - 48); j += 1; end; if Res < 0 then if (Res = -2147483648) and (sign = -1) then exit else begin Result := False; exit end; if sign = -1 then Res := -Res; while (j <= s.Length) and char.IsWhiteSpace(s[j]) do j += 1; if j <= s.Length then begin Result := False; exit end; value := Res; end; function StrToInt64(s: string) := Convert.ToInt64(s); function StrToReal(s: string; nfi: NumberFormatInfo) := Convert.ToDouble(s, nfi); function StrToReal(s: string) := StrToReal(s, nfi); function StrToReal(s: string; DecimalSeparator: string): real := StrToReal(s, NumberFormat(DecimalSeparator)); function StrToFloat(s: string; nfi: NumberFormatInfo) := StrToReal(s, nfi); function StrToFloat(s: string) := StrToReal(s); function StrToFloat(s: string; DecimalSeparator: string): real := StrToReal(s, DecimalSeparator); function TryStrToInt64(s: string; var value: int64) := int64.TryParse(s, value); function TryStrToReal(s: string; var value: real) := real.TryParse(s,System.Globalization.NumberStyles.Float,new System.Globalization.NumberFormatInfo,value); function TryStrToSingle(s: string; var value: single) := single.TryParse(s,System.Globalization.NumberStyles.Float,new System.Globalization.NumberFormatInfo,value); function TryStrToFloat(s: string; var value: real) := TryStrToReal(s, value); function TryStrToFloat(s: string; var value: single) := TryStrToSingle(s, value); function ReadIntegerFromString(s: string; var from: integer): integer; begin while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; if (from > s.Length) then raise new System.FormatException(GetTranslation(Format_InvalidString)); var sign := 0; if s[from] = '-' then begin sign := -1; from += 1; end else if s[from] = '+' then begin sign := 1; from += 1; end; if (from > s.Length) then raise new System.FormatException(GetTranslation(Format_InvalidString)); var c := integer(s[from]); if (c < 48) or (c > 57) then raise new System.FormatException(GetTranslation(Format_InvalidString)); Result := c - 48; from += 1; while from <= s.Length do begin c := integer(s[from]); if c > 57 then break; if c < 48 then break; if Result > 214748364 then raise new System.OverflowException(GetTranslation(Overflow_Int32)); Result := Result * 10 + (c - 48); from += 1; end; if Result < 0 then if (Result = -2147483648) and (sign = -1) then exit else raise new System.OverflowException(GetTranslation(Overflow_Int32)); if sign = -1 then Result := -Result; end; function ReadWordFromString(s: string; var from: integer): string; begin while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; var res := new System.Text.StringBuilder(); while (from <= s.Length) and not char.IsWhiteSpace(s[from]) do begin res.Append(s[from]); from += 1; end; Result := res.ToString; end; function ReadRealFromString(s: string; var from: integer): real; begin Result := real.Parse(ReadWordFromString(s, from)); end; function TryReadRealFromString(s: string; var from: integer; var res: real): boolean; begin Result := real.TryParse(ReadWordFromString(s, from), res); end; function StringIsEmpty(s: string; var from: integer): boolean; begin while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; Result := from > s.Length; end; function TryReadIntegerFromString(s: string; var from: integer; var res: integer): boolean; begin Result := TryStrToInt(ReadWordFromString(s, from), res); end; procedure Val(s: string; var value: integer; var err: integer); begin if TryStrToInt(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: real; var err: integer); begin if TryStrToFloat(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: single; var err: integer); begin try err := 0; value := Convert.ToSingle(s, nfi); except value := 0; err := 1; end; end; procedure Val(s: string; var value: shortint; var err: integer); begin if shortint.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: smallint; var err: integer); begin if smallint.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: int64; var err: integer); begin if int64.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: byte; var err: integer); begin if byte.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: word; var err: integer); begin if word.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: longword; var err: integer); begin if longword.TryParse(s, value) then err := 0 else err := 1; end; procedure Val(s: string; var value: uint64; var err: integer); begin if uint64.TryParse(s, value) then err := 0 else err := 1; end; function IntToStr(a: integer): string; begin Result := a.ToString; end; function IntToStr(a: int64): string; begin Result := a.ToString; end; function FloatToStr(a: real; nfi: NumberFormatInfo): string := a.ToString(nfi); function FloatToStr(a: real): string := FloatToStr(a, nfi); function Format(formatstring: string; params pars: array of object): string; begin try Result := string.Format(nfi, formatstring, pars); except on e: Exception do raise e; end; end; // ----------------------------------------------------- // Общие подпрограммы // ----------------------------------------------------- procedure Inc(var i: integer); begin i += 1; end; procedure Inc(var i: integer; n: integer); begin i += n; end; procedure Dec(var i: integer); begin i -= 1; end; procedure Dec(var i: integer; n: integer); begin i -= n; end; procedure Inc(var c: char); begin c := ChrUnicode(word(c) + 1); end; procedure Inc(var c: char; n: integer); begin c := ChrUnicode(word(c) + n); end; procedure Dec(var c: char); begin c := ChrUnicode(word(c) - 1); end; procedure Dec(var c: char; n: integer); begin c := ChrUnicode(word(c) - n); end; procedure Inc(var b: byte); begin b += 1; end; procedure Inc(var b: byte; n: integer); begin b += n; end; procedure Dec(var b: byte); begin b -= 1; end; procedure Dec(var b: byte; n: integer); begin b -= n; end; procedure Inc(var f: boolean); begin f := not f; end; procedure Dec(var f: boolean); begin f := not f; end; //------------------------------------------------------------------------------ //PRED-SUCC function Succ(x: boolean): boolean; begin Result := not x; end; function Succ(x: byte): byte; begin Result := x + 1; end; function Succ(x: shortint): shortint; begin Result := x + 1; end; function succ(x: smallint): smallint; begin Result := x + 1; end; function Succ(x: word): word; begin Result := x + 1; end; function Succ(x: integer): integer; begin Result := x + 1; end; function Succ(x: longword): longword; begin Result := x + 1; end; function Succ(x: int64): int64; begin Result := x + 1; end; function Succ(x: uint64): uint64; begin Result := x + 1; end; function Succ(x: char): char; begin //Result := System.Convert.ToChar(System.Convert.ToUInt16(x) + 1); Result := char(integer(x)+1); end; function Succ(x: char; n: integer): char; begin //Result := System.Convert.ToChar(System.Convert.ToUInt16(x) + 1); Result := char(integer(x)+n); end; function Pred(x: boolean): boolean; begin Result := not x; end; function Pred(x: byte): byte; begin Result := x - 1; end; function Pred(x: shortint): shortint; begin Result := x - 1; end; function Pred(x: smallint): smallint; begin Result := x - 1; end; function Pred(x: word): word; begin Result := x - 1; end; function Pred(x: integer): integer; begin Result := x - 1; end; function Pred(x: longword): longword; begin Result := x - 1; end; function Pred(x: int64): int64; begin Result := x - 1; end; function Pred(x: uint64): uint64; begin Result := x - 1; end; function Pred(x: char): char; begin Result := char(integer(x)-1); //Result := System.Convert.ToChar(System.Convert.ToUInt16(x) - 1); end; function Pred(x: char; n: integer): char; begin Result := char(integer(x)-n); end; /// Возвращает True, если значение val находится между a и b включительно function InRange(val, a, b: T): boolean; where T: IComparable; begin Result := (val.CompareTo(a) >= 0) and (val.CompareTo(b) <= 0); end; /// Возвращает True, если значение val находится между a и b (включительно) независимо от порядка a и b function Between(val, a, b: T): boolean; where T: IComparable; begin if a.CompareTo(b) > 0 then Result := (val.CompareTo(b) >= 0) and (val.CompareTo(a) <= 0) else Result := (val.CompareTo(a) >= 0) and (val.CompareTo(b) <= 0); end; procedure Swap(var a, b: T); begin var v := a; a := b; b := v; end; //{{{doc: Начало методов расширения }}} // ----------------------------------------------------- //>> Генерация бесконечных последовательностей # Infinite sequences // ----------------------------------------------------- // Дополнения февраль 2016: Iterate, Step, &Repeat, Cycle // Возвращает бесконечную рекуррентную последовательность элементов, задаваемую начальным элементом и функцией next ///-- function Iterate(Self: T; next: T->T): sequence of T; extensionmethod; begin Result := Iterate&(Self, next); end; // Возвращает бесконечную рекуррентную последовательность элементов, задаваемую начальным элементом, следующим за ним элементом и функцией next ///-- function Iterate(Self, second: T; next: (T,T) ->T): sequence of T; extensionmethod; begin Result := Iterate&(Self, second, next); end; /// Возвращает бесконечную последовательность целых от текущего значения с шагом 1 function Step(Self: integer): sequence of integer; extensionmethod; begin while True do begin yield Self; Self += 1; end; end; /// Возвращает бесконечную последовательность целых от текущего значения с шагом step function Step(Self: integer; step: integer): sequence of integer; extensionmethod; begin while True do begin yield Self; Self += step; end; end; /// Возвращает бесконечную последовательность вещественных от текущего значения с шагом step function Step(Self: real; step: real): sequence of real; extensionmethod; begin while True do begin yield Self; Self += step; end; end; // Возвращает бесконечную последовательность элементов, совпадающих с данным ///-- function &Repeat(Self: T): sequence of T; extensionmethod; begin while True do yield Self; end; /// Повторяет последовательность бесконечное число раз function Cycle(Self: sequence of T): sequence of T; extensionmethod; begin while True do begin foreach var x in Self do yield x; end; end; // ----------------------------------------------------- //>> Фиктивная секция XXX - не удалять! # XXX // ----------------------------------------------------- type AdjGroupClass = class private cur: T; enm: IEnumerator; fin: boolean; public constructor Create(a: sequence of T); begin enm := a.GetEnumerator(); fin := enm.MoveNext; if fin then cur := enm.Current; end; function TakeGroup: sequence of T; begin yield cur; fin := enm.movenext; while fin do begin if enm.current = cur then yield enm.current else begin cur := enm.Current; break; end; fin := enm.movenext; end; end; end; //------------------------------------------------------------------------------ //>> Метод расширения Print для элементарных типов # Print for elementary types //------------------------------------------------------------------------------ /// Выводит значение на экран, после чего выводит пробел function Print(Self: integer): integer; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: int64): int64; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: real): real; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: char): char; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: boolean): boolean; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: BigInteger): BigInteger; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран, после чего выводит пробел function Print(Self: string): string; extensionmethod; begin PABCSystem.Print(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: integer): integer; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: int64): int64; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: real): real; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: char): char; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: boolean): boolean; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: BigInteger): BigInteger; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; /// Выводит значение на экран и переходит на новую строку function Println(Self: string): string; extensionmethod; begin PABCSystem.Println(Self); Result := Self; end; //------------------------------------------------------------------------------ //>> Методы расширения последовательностей # Extension methods for sequence of T //------------------------------------------------------------------------------ /// Выводит последовательность на экран, используя delim в качестве разделителя function Print(Self: sequence of T; delim: string): sequence of T; extensionmethod; begin var g := Self.GetEnumerator(); if g.MoveNext() then begin Write(g.Current); while g.MoveNext() do if delim <> '' then Write(delim, g.Current) else Write(g.Current); end; Result := Self; end; /// Выводит последовательность на экран, используя пробел в качестве разделителя function Print(Self: sequence of T): sequence of T; extensionmethod; begin if typeof(T) = typeof(char) then Result := Self.Print('') else Result := Self.Print(PrintDelimDefault); end; /// Выводит последовательность на экран, используя delim в качестве разделителя, и переходит на новую строку function Println(Self: sequence of T; delim: string): sequence of T; extensionmethod; begin Self.Print(delim); Writeln; Result := Self; end; /// Выводит последовательность на экран, используя пробел качестве разделителя, и переходит на новую строку function Println(Self: sequence of T): sequence of T; extensionmethod; begin if typeof(T) = typeof(char) then Result := Self.Println('') else Result := Self.Println(PrintDelimDefault); end; /// Выводит последовательность строк в файл function WriteLines(Self: sequence of string; fname: string): sequence of string; extensionmethod; begin WriteLines(fname, Self); Result := Self end; /// Выводит последовательность, каждый элемент выводится на новой строке function PrintLines(Self: sequence of T): sequence of T; extensionmethod; begin Self.Println(NewLine); Result := Self end; /// Выводит последовательность, каждый элемент отображается с помощью функции map и выводится на новой строке function PrintLines(Self: sequence of T; map: T->T1): sequence of T; extensionmethod; begin Self.Select(map).Println(NewLine); Result := Self end; /// Преобразует последовательность последовательностей в плоскую последовательность function Flatten(Self: sequence of sequence of T): sequence of T; extensionmethod := Self.SelectMany(x -> x); /// Преобразует элементы последовательности в строковое представление, после чего объединяет их в строку, используя delim в качестве разделителя function JoinToString(Self: sequence of T; delim: string): string; extensionmethod; begin var g := Self.GetEnumerator(); var sb := new System.Text.StringBuilder(''); if g.MoveNext() then begin sb.Append(g.Current.ToString()); while g.MoveNext() do sb.Append(delim + g.Current.ToString()); end; Result := sb.ToString; end; ///-- function JoinIntoString(Self: sequence of T; delim: string): string; extensionmethod := Self.JoinToString(delim); /// Преобразует элементы последовательности в строковое представление, после чего объединяет их в строку, используя пробел в качестве разделителя function JoinToString(Self: sequence of T): string; extensionmethod; begin if typeof(T) = typeof(char) then Result := Self.JoinIntoString('') else Result := Self.JoinIntoString(' '); end; ///-- function JoinIntoString(Self: sequence of T): string; extensionmethod := Self.JoinToString(); /// Применяет действие к каждому элементу последовательности procedure &ForEach(Self: sequence of T; action: T -> ()); extensionmethod; begin foreach x: T in Self do action(x); end; /// Применяет действие к каждому элементу последовательности, зависящее от номера элемента procedure &ForEach(Self: sequence of T; action: (T,integer) -> ()); extensionmethod; begin var i := 0; foreach x: T in Self do begin action(x, i); i += 1; end; end; /// Возвращает произведение элементов последовательности function Product(Self: sequence of real): real; extensionmethod; begin Result := 1.0; foreach var x in Self do Result *= x; end; /// Возвращает произведение элементов последовательности function Product(Self: sequence of integer): int64; extensionmethod; begin Result := 1; foreach var x in Self do Result *= x; end; /// Возвращает произведение элементов последовательности, спроектированных на числовое значение function Product(Self: sequence of T; f: T->real): real; extensionmethod; begin Result := 1.0; foreach var x in Self do Result *= f(x); end; /// Возвращает произведение элементов последовательности, спроектированных на числовое значение function Product(Self: sequence of T; f: T->integer): int64; extensionmethod; begin Result := 1; foreach var x in Self do Result *= f(x); end; /// Возвращает произведение элементов последовательности, спроектированных на числовое значение function Product(Self: sequence of T; f: T->BigInteger): BigInteger; extensionmethod; begin Result := 1; foreach var x in Self do Result *= f(x); end; /// Возвращает последовательность частичных сумм элементов последовательности function PartialSum(Self: sequence of integer): sequence of integer; extensionmethod; begin var s := 0; foreach var item in Self do begin s += item; yield s; end; end; /// Возвращает последовательность частичных сумм элементов последовательности function PartialSum(Self: sequence of real): sequence of real; extensionmethod; begin var s := 0.0; foreach var item in Self do begin s += item; yield s; end; end; /// Возвращает последовательность частичных сумм элементов последовательности function PartialSum(Self: sequence of BigInteger): sequence of BigInteger; extensionmethod; begin var s := 0bi; foreach var item in Self do begin s += item; yield s; end; end; // SSM 14/3/2024 - Scan /// Возвращает последовательность, в которой первый элемент равен первому элементу исходной последовательности, а каждый следующий - ///результат применения функции func к предыдущему элементу новой последовательности и текущему элементу исходной function Scan(Self: sequence of T; func: (T,T) -> T): sequence of T; extensionmethod; begin var e := Self.GetEnumerator; if not e.MoveNext then exit; var s := e.Current; yield s; while e.MoveNext do begin s := func(s,e.Current); yield s; end; end; /// Возвращает последовательность, в которой первый элемент равен first, а каждый следующий - ///результат применения функции func к предыдущему элементу новой последовательности и текущему элементу исходной function Scan(Self: sequence of T; first: T1; func: (T1,T) -> T1): sequence of T1; extensionmethod; begin var e := Self.GetEnumerator; var s := first; yield s; while e.MoveNext do begin s := func(s,e.Current); yield s; end; end; // Возвращает сумму элементов последовательности, спроектированных на числовое значение - пока не работает для Lst(1,2,3) {function Sum(Self: sequence of T; f: T->BigInteger): BigInteger; extensionmethod; begin Result := 0; foreach var x in Self do Result += f(x); end;} // SSM 23/11/2020 - Sum Average Product for sequence of BigInteger /// Возвращает сумму элементов последовательности function Sum(Self: sequence of BigInteger): BigInteger; extensionmethod; begin Result := 0bi; foreach var a in Self do Result += a end; /// Возвращает среднее элементов последовательности function Average(Self: sequence of BigInteger): real; extensionmethod; begin var cnt := 0; var sum := 0bi; foreach var a in Self do begin sum += a; cnt += 1; end; if cnt <> 0 then Result := sum/cnt else Result := 0 end; /// Возвращает произведение элементов последовательности function Product(Self: sequence of BigInteger): BigInteger; extensionmethod; begin Result := 1bi; foreach var a in Self do Result *= a end; /// Возвращает отсортированную по возрастанию последовательность function Sorted(Self: sequence of T): sequence of T; extensionmethod; begin Result := Self.OrderBy(x -> x); end; /// Возвращает отсортированную по убыванию последовательность function SortedDescending(Self: sequence of T): sequence of T; extensionmethod; begin Result := Self.OrderByDescending(x -> x); end; /// Возвращает отсортированную по возрастанию последовательность function Order(Self: sequence of T): sequence of T; extensionmethod; begin Result := Self.OrderBy(x -> x); end; /// Возвращает отсортированную по убыванию последовательность function OrderDescending(Self: sequence of T): sequence of T; extensionmethod; begin Result := Self.OrderByDescending(x -> x); end; /// Возвращает отсортированную по возрастанию последовательность function Order(Self: sequence of string): sequence of string; extensionmethod; begin Result := Self.OrderBy(x -> x, System.StringComparer.Ordinal); end; /// Возвращает отсортированную по убыванию последовательность function OrderDescending(Self: sequence of string): sequence of string; extensionmethod; begin Result := Self.OrderByDescending(x -> x, System.StringComparer.Ordinal); end; /// Проверяет, отсортирована ли последовательность по возрастанию ключа, используя компаратор function IsOrderedBy(self: sequence of T; keySelector: T -> TKey; comparer: IComparer): boolean; extensionmethod; begin var prevKey: TKey; var first := True; foreach var item in self do begin var currentKey := keySelector(item); if not first and (comparer.Compare(prevKey, currentKey) > 0) then exit(False); prevKey := currentKey; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по возрастанию ключа function IsOrderedBy(self: sequence of T; keySelector: T -> TKey): boolean; extensionmethod; where TKey: System.IComparable; begin Result := self.IsOrderedBy(keySelector, Comparer&.Default); end; /// Проверяет, отсортирована ли последовательность по возрастанию в порядке, заданном компаратором comparer function IsOrdered(self: sequence of T; comparer: IComparer): boolean; extensionmethod; begin var prev: T; var first := True; foreach var current in self do begin if not first and (comparer.Compare(prev, current) > 0) then exit(False); prev := current; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по возрастанию function IsOrdered(self: sequence of T): boolean; extensionmethod; where T: System.IComparable; begin var prev: T; var first := True; foreach var current in self do begin if not first and (prev.CompareTo(current) > 0) then exit(False); prev := current; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по убыванию ключа, используя компаратор function IsOrderedByDescending(self: sequence of T; keySelector: T -> TKey; comparer: IComparer): boolean; extensionmethod; begin var prevKey: TKey; var first := True; foreach var item in self do begin var currentKey := keySelector(item); if not first and (comparer.Compare(prevKey, currentKey) < 0) then exit(False); prevKey := currentKey; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по убыванию ключа function IsOrderedByDescending(self: sequence of T; keySelector: T -> TKey): boolean; extensionmethod; where TKey: System.IComparable; begin var prevKey: TKey; var first := True; foreach var item in self do begin var currentKey := keySelector(item); if not first and (prevKey.CompareTo(currentKey) < 0) then exit(False); prevKey := currentKey; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по убыванию function IsOrderedDescending(self: sequence of T): boolean; extensionmethod; where T: System.IComparable; begin var prev: T; var first := True; foreach var current in self do begin if not first and (prev.CompareTo(current) < 0) then exit(False); prev := current; first := False; end; Result := True; end; /// Проверяет, отсортирована ли последовательность по убыванию в порядке, заданном компаратором comparer function IsOrderedDescending(self: sequence of T; comparer: IComparer): boolean; extensionmethod; begin var prev: T; var first := True; foreach var current in self do begin if not first and (comparer.Compare(prev, current) < 0) then // Обратный знак exit(False); prev := current; first := False; end; Result := True; end; /// Возвращает множество HashSet по данной последовательности function ToHashSet(Self: sequence of T): HashSet; extensionmethod; begin Result := new HashSet(Self); end; /// Возвращает множество по данной последовательности function ToSet(Self: sequence of T): NewSet; extensionmethod; begin Result._hs := new HashSet(Self); end; /// Возвращает множество SortedSet по данной последовательности function ToSortedSet(Self: sequence of T): SortedSet; extensionmethod; begin Result := new SortedSet(Self); end; /// Возвращает LinkedList по данной последовательности function ToLinkedList(Self: sequence of T): LinkedList; extensionmethod; begin Result := new LinkedList(Self); end; // Дополнения февраль 2016: MinBy, MaxBy, TakeLast, Slice, Cartesian, SplitAt, // Partition, ZipTuple, UnZipTuple, Interleave, Numerate, Tabulate, Pairwise, Batch // Дополнения 2024: Zip - синоним ZipTuple /// Возвращает первый элемент последовательности с минимальным значением ключа function MinBy(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod; begin var enumerator := Self.GetEnumerator(); if not enumerator.MoveNext() then raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY)); var minElement := enumerator.Current; var minKey := keySelector(minElement); var comp := Comparer&.Default; while enumerator.MoveNext() do begin var currentElement := enumerator.Current; var currentKey := keySelector(currentElement); if comp.Compare(currentKey,minKey) < 0 then begin minKey := currentKey; minElement := currentElement; end; end; Result := minElement; end; /// Возвращает первый элемент последовательности с максимальным значением ключа function MaxBy(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod; begin var enumerator := Self.GetEnumerator(); if not enumerator.MoveNext() then raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY)); var maxElement := enumerator.Current; var maxKey := keySelector(maxElement); var comp := Comparer&.Default; while enumerator.MoveNext() do begin var currentElement := enumerator.Current; var currentKey := keySelector(currentElement); if comp.Compare(currentKey,maxKey) > 0 then begin maxKey := currentKey; maxElement := currentElement; end; end; Result := maxElement; end; /// Возвращает последний элемент последовательности с минимальным значением ключа function LastMinBy(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod; begin var enumerator := Self.GetEnumerator(); if not enumerator.MoveNext() then raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY)); var minElement := enumerator.Current; var minKey := keySelector(minElement); var comp := Comparer&.Default; while enumerator.MoveNext() do begin var currentElement := enumerator.Current; var currentKey := keySelector(currentElement); if comp.Compare(currentKey,minKey) <= 0 then begin minKey := currentKey; minElement := currentElement; end; end; Result := minElement; end; /// Возвращает последний элемент последовательности с максимальным значением ключа function LastMaxBy(Self: sequence of T; keySelector: T -> TKey): T; extensionmethod; begin var enumerator := Self.GetEnumerator(); if not enumerator.MoveNext() then raise new System.ArgumentException(GetTranslation(SEQUENCE_CANNOT_BE_EMPTY)); var maxElement := enumerator.Current; var maxKey := keySelector(maxElement); var comp := Comparer&.Default; while enumerator.MoveNext() do begin var currentElement := enumerator.Current; var currentKey := keySelector(currentElement); if comp.Compare(currentKey,maxKey) > 0 then begin maxKey := currentKey; maxElement := currentElement; end; end; Result := maxElement; end; {function TakeLast(Self: sequence of T; count: integer): sequence of T; extensionmethod; begin if count < 0 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_EQUAL_0)); if Self is IList then begin var lst := Self as IList; var ind := lst.Count - count; if ind<0 then ind := 0; for var i:=ind to lst.Count-1 do yield lst[i]; exit; end; var buf := new List; var p := 0; foreach var x in Self do if buf.Count(Self: sequence of T; count: integer): sequence of T; extensionmethod; begin Result := Self.Reverse.Take(count).Reverse; end; {function SkipLast(Self: sequence of T; count: integer): sequence of T; extensionmethod; begin if count < 0 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_EQUAL_0)); if Self is IList then begin var lst := Self as IList; for var i:=0 to lst.Count - count - 1 do yield lst[i]; exit; end; var buf := new List(count); var p := 0; foreach var x in Self do if buf.Count(Self: sequence of T): sequence of T; extensionmethod := Self.SkipLast(1);} /// Возвращает последовательность без последних count элементов function SkipLast(self: sequence of T; count: integer := 1): sequence of T; extensionmethod; begin Result := Self.Reverse.Skip(count).Reverse; end; /// Разбивает последовательность на две в позиции ind. Реализуется двухпроходным алгоритмом function SplitAt(Self: sequence of T; ind: integer): (sequence of T, sequence of T); extensionmethod; begin Result := (Self.Take(ind), Self.Skip(ind)); end; // ToDo: то же для TakeWhile // ToDo: SequenceCompare /// Разделяет последовательность на две по заданному условию. Реализуется двухпроходным алгоритмом function Partition(Self: sequence of T; cond: T->boolean): (sequence of T, sequence of T); extensionmethod; begin Result := (Self.Where(cond), Self.Where(x -> not cond(x))); end; /// Разделяет последовательность на две по заданному условию, в котором участвует индекс. Реализуется двухпроходным алгоритмом function Partition(Self: sequence of T; cond: (T,integer)->boolean): (sequence of T, sequence of T); extensionmethod; begin Result := (Self.Where(cond), Self.Where((x, i) -> not cond(x, i))); end; /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2; func: (T,T1,T2) -> TRes): sequence of TRes; extensionmethod := Zip(Self,b,c,func); /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; func: (T,T1,T2,T3) -> TRes): sequence of TRes; extensionmethod := Zip(Self,b,c,d,func); /// Применяет указанную функцию к соответствующим элементам кортежей, возвращает последовательность результатов function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; func: (T,T1,T2,T3,T4) -> TRes): sequence of TRes; extensionmethod := Zip(Self,b,c,d,e,func); /// Объединяет две последовательности в последовательность двухэлементных кортежей function Zip(Self: sequence of T; b: sequence of T1): sequence of (T, T1); extensionmethod := Zip(Self,b); /// Объединяет три последовательности в последовательность трехэлементных кортежей function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2); extensionmethod := Zip(Self,b,c); /// Объединяет четыре последовательности в последовательность четырехэлементных кортежей function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3); extensionmethod := Zip(Self,b,c,d); /// Объединяет четыре последовательности в последовательность четырехэлементных кортежей function Zip(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4); extensionmethod := Zip(Self,b,c,d,e); /// Возвращает декартово произведение последовательностей, проектируя каждую пару на значение function Cartesian(Self: sequence of T; b: sequence of T1; func: (T,T1)->TRes): sequence of TRes; extensionmethod := Cartesian(Self,b,func); /// Возвращает декартово произведение последовательностей, проектируя каждую тройку на значение function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2; func: (T,T1,T2)->TRes): sequence of TRes; extensionmethod := Cartesian(Self,b,c,func); /// Возвращает декартово произведение последовательностей, проектируя каждую четвёрку на значение function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; func: (T,T1,T2,T3)->TRes): sequence of TRes; extensionmethod := Cartesian(Self,b,c,d,func); /// Возвращает декартово произведение последовательностей, проектируя каждую пятёрку на значение function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4; func: (T,T1,T2,T3,T4)->TRes): sequence of TRes; extensionmethod := Cartesian(Self,b,c,d,e,func); /// Возвращает декартово произведение последовательностей в виде последовательности пар function Cartesian(Self: sequence of T; b: sequence of T1): sequence of (T, T1); extensionmethod := Cartesian(Self,b); /// Возвращает декартово произведение последовательностей в виде последовательности троек function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2): sequence of (T, T1, T2); extensionmethod := Cartesian(Self,b,c); /// Возвращает декартово произведение последовательностей в виде последовательности четвёрок function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3): sequence of (T, T1, T2, T3); extensionmethod := Cartesian(Self,b,c,d); /// Возвращает декартово произведение последовательностей в виде последовательности пятёрок function Cartesian(Self: sequence of T; b: sequence of T1; c: sequence of T2; d: sequence of T3; e: sequence of T4): sequence of (T, T1, T2, T3, T4); extensionmethod := Cartesian(Self,b,c,d,e); /// Объединяет две последовательности в последовательность двухэлементных кортежей function ZipTuple(Self: sequence of T; a: sequence of T1): sequence of (T, T1); extensionmethod := Self.Zip(a); /// Объединяет три последовательности в последовательность трехэлементных кортежей function ZipTuple(Self: sequence of T; a: sequence of T1; b: sequence of T2): sequence of (T, T1, T2); extensionmethod := Self.Zip(a,b); /// Объединяет четыре последовательности в последовательность четырехэлементных кортежей function ZipTuple(Self: sequence of T; a: sequence of T1; b: sequence of T2; c: sequence of T3): sequence of (T, T1, T2, T3); extensionmethod := Self.Zip(a,b,c); /// Разъединяет последовательность двухэлементных кортежей на две последовательности. Реализуется двухпроходным алгоритмом function UnZipTuple(Self: sequence of (T, T1)): (sequence of T, sequence of T1); extensionmethod; begin Result := (Self.Select(x -> x[0]), Self.Select(x -> x[1])) end; /// Разъединяет последовательность трехэлементных кортежей на три последовательности. Реализуется многопроходным алгоритмом function UnZipTuple(Self: sequence of (T, T1, T2)): (sequence of T, sequence of T1, sequence of T2); extensionmethod; begin Result := (Self.Select(x -> x[0]), Self.Select(x -> x[1]), Self.Select(x -> x[2])) end; /// Разъединяет последовательность четырехэлементных кортежей на четыре последовательности. Реализуется многопроходным алгоритмом function UnZipTuple(Self: sequence of (T, T1, T2, T3)): (sequence of T, sequence of T1, sequence of T2, sequence of T3); extensionmethod; begin Result := (Self.Select(x -> x[0]), Self.Select(x -> x[1]), Self.Select(x -> x[2]), Self.Select(x -> x[3])) end; // ToDo - сделать UnZipTuple с функцией-проекцией /// Чередует элементы двух последовательностей function Interleave(Self: sequence of T; a: sequence of T): sequence of T; extensionmethod; begin if a = nil then raise new System.ArgumentNullException('a'); Result := Self.ZipTuple(a).SelectMany(x -> Seq(x[0], x[1])) end; /// Чередует элементы трех последовательностей function Interleave(Self: sequence of T; a, b: sequence of T): sequence of T; extensionmethod; begin if a = nil then raise new System.ArgumentNullException('a'); if b = nil then raise new System.ArgumentNullException('b'); Result := Self.ZipTuple(a, b).SelectMany(x -> Seq(x[0], x[1], x[2])) end; /// Чередует элементы четырех последовательностей function Interleave(Self: sequence of T; a, b, c: sequence of T): sequence of T; extensionmethod; begin if a = nil then raise new System.ArgumentNullException('a'); if b = nil then raise new System.ArgumentNullException('b'); if c = nil then raise new System.ArgumentNullException('c'); Result := Self.ZipTuple(a, b, c).SelectMany(x -> Seq(x[0], x[1], x[2], x[3])) end; /// Нумерует последовательность с единицы function Numerate(Self: sequence of T): sequence of (integer, T); extensionmethod; begin var i := 1; foreach var x in Self do begin yield (i,x); i += 1; end; end; /// Нумерует последовательность с номера from function Numerate(Self: sequence of T; from: integer): sequence of (integer, T); extensionmethod; begin var i := from; foreach var x in Self do begin yield (i,x); i += 1; end; end; /// Табулирует функцию последовательностью function Tabulate(Self: sequence of T; F: T->T1): sequence of (T, T1); extensionmethod; begin Result := Self.Select(x -> (x, f(x))); end; /// Превращает последовательность в последовательность пар соседних элементов function Pairwise(Self: sequence of T): sequence of (T, T); extensionmethod; begin var previous: T; var it := Self.GetEnumerator(); if (it.MoveNext()) then begin previous := it.Current; while (it.MoveNext()) do begin yield (previous, it.Current); previous := it.Current; end; end; end; /// Превращает последовательность в последовательность массивов, содержащих n соседних элементов function Nwise(Self: sequence of T; n: integer): sequence of array of T; extensionmethod; begin var chunk := new Queue(n); foreach var x in Self do begin chunk.Enqueue(x); if chunk.Count = n then begin yield chunk.ToArray; chunk.Dequeue; end; end; end; /// Превращает последовательность в последовательность пар соседних элементов, применяет func к каждой паре полученных элементов и получает новую последовательность function Pairwise(Self: sequence of T; func: (T,T)->Res): sequence of Res; extensionmethod; begin var previous: T; var it := Self.GetEnumerator(); if (it.MoveNext()) then begin previous := it.Current; while (it.MoveNext()) do begin yield func(previous, it.Current); previous := it.Current; end; end; // Result := Self.ZipTuple(Self.Skip(1)).Select(x->func(x[0],x[1])); end; /// Разбивает последовательность на серии длины size function Batch(Self: sequence of T; size: integer): sequence of array of T; extensionmethod; begin var buf := new List(size); foreach var elm in Self do begin buf.Add(elm); if buf.Count=size then begin yield buf.ToArray; buf.Clear end; end; if buf.Count>0 then yield buf.ToArray; //Result := SeqWhile(Self, v -> v.Skip(size), v -> v.Count > 0).Select(v -> v.Take(size)) end; /// Разбивает последовательность на серии длины size и применяет проекцию к каждой серии function Batch(Self: sequence of T; size: integer; proj: Func): sequence of Res; extensionmethod; begin //Result := SeqWhile(Self, v -> v.Skip(size), v -> v.Count > 0).Select(v -> v.Take(size)).Select(ss -> proj(ss)); Result := Self.Batch(size).Select(proj); end; ///-- function SliceSeqImpl(Self: sequence of T; from, step, count: integer): sequence of T; begin if step <= 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_GREATER_0)); if from < 0 then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); Result := Self.Skip(from).Where((x, i)-> i mod step = 0) end; /// Возвращает срез последовательности от номера from с шагом step > 0 function Slice(Self: sequence of T; from, step: integer): sequence of T; extensionmethod; begin if step <= 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_GREATER_0)); if from < 0 then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); Result := Self.Skip(from).Where((x, i)-> i mod step = 0) end; /// Возвращает срез последовательности от номера from с шагом step > 0 длины не более count function Slice(Self: sequence of T; from, step, count: integer): sequence of T; extensionmethod; begin if step <= 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_GREATER_0)); if from < 0 then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); Result := Self.Skip(from).Where((x, i)-> i mod step = 0).Take(count) end; // Дополнения июль 2016: Incremental ///-- function IncrementalSeq(Self: sequence of integer): sequence of integer; begin var iter := Self.GetEnumerator(); if iter.MoveNext() then begin var prevItem := iter.Current; while iter.MoveNext() do begin var nextItem := iter.Current; yield nextItem - prevItem; prevItem := nextItem; end end end; ///-- function IncrementalSeq(Self: sequence of real): sequence of real; begin var iter := Self.GetEnumerator(); if iter.MoveNext() then begin var prevItem := iter.Current; while iter.MoveNext() do begin var nextItem := iter.Current; yield nextItem - prevItem; prevItem := nextItem; end end end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: sequence of integer): sequence of integer; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: array of integer): sequence of integer; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: List): sequence of integer; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: LinkedList): sequence of integer; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: sequence of real): sequence of real; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: array of real): sequence of real; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: List): sequence of real; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности function Incremental(Self: LinkedList): sequence of real; extensionmethod; begin Result := IncrementalSeq(Self); end; /// Возвращает последовательность разностей соседних элементов исходной последовательности. В качестве функции разности используется func function Incremental(Self: sequence of T; func: (T,T)->T1): sequence of T1; extensionmethod; begin var iter := Self.GetEnumerator(); if iter.MoveNext() then begin var prevItem := iter.Current; while iter.MoveNext() do begin var nextItem := iter.Current; yield func(prevItem, nextItem); prevItem := nextItem; end end end; /// Возвращает последовательность разностей соседних элементов исходной последовательности. В качестве функции разности используется func function Incremental(Self: sequence of T; func: (T,T,integer)->T1): sequence of T1; extensionmethod; begin var iter := Self.GetEnumerator(); if iter.MoveNext() then begin var ind := 0; var prevItem := iter.Current; while iter.MoveNext() do begin var nextItem := iter.Current; ind += 1; yield func(prevItem, nextItem, ind); prevItem := nextItem; end end end; /// Группирует одинаковые подряд идущие элементы, получая последовательность массивов function AdjacentGroup(Self: sequence of T): sequence of array of T; extensionmethod; begin var c := new AdjGroupClass(Self); while c.fin do yield c.TakeGroup().ToArray; end; // ToDo Сделать AdjacentGroup с функцией сравнения /// Возвращает количество элементов, равных указанному значению function CountOf(Self: sequence of T; x: T): integer; extensionmethod; begin Result := 0; foreach var y in Self do if y = x then Result += 1; end; /// Возвращает элементы последовательности, ключи для которых отличаются, используя компоратор comp function DistinctBy(Self: sequence of T; by: T->TKey; comp: IEqualityComparer): sequence of T; extensionmethod; begin var hs := new HashSet(comp); foreach var x in Self do if hs.Add(by(x)) then yield x; end; /// Возвращает элементы последовательности, ключи для которых отличаются, используя компоратор по-умолчанию function DistinctBy(Self: sequence of T; by: T->TKey); extensionmethod := Self.DistinctBy(by, nil); // ----------------------------------------------------- //>> Методы расширения списков # Extension methods for List T // ----------------------------------------------------- /// Возвращает случайный элемент списка function RandomElement(Self: List): T; extensionmethod; begin Result := Self[Random(Self.Count)]; end; /// Возвращает последовательность индексов списка function Indices(Self: List): sequence of integer; extensionmethod := Range(0, Self.Count - 1); /// Возвращает последовательность индексов элементов списка, удовлетворяющих условию function Indices(Self: List; cond: T->boolean): sequence of integer; extensionmethod; begin for var i := 0 to Self.Count - 1 do if cond(Self[i]) then yield i; end; /// Возвращает последовательность индексов элементов списка, удовлетворяющих условию function Indices(Self: List; cond: (T,integer) ->boolean): sequence of integer; extensionmethod; begin for var i := 0 to Self.Count - 1 do if cond(Self[i], i) then yield i; end; /// Перемешивает элементы списка случайным образом function Shuffle(Self: List): List; extensionmethod; begin for var i := Self.Count - 1 downto 1 do begin var r := Random(i + 1); var v := Self[i]; Self[i] := Self[r]; Self[r] := v; end; Result := Self; end; /// Находит первую пару подряд идущих одинаковых элементов и возвращает индекс первого элемента пары. Если не найден, возвращается -1 function AdjacentFind(Self: IList; start: integer := 0): integer; extensionmethod; begin Result := -1; for var i := start to Self.Count - 2 do if Self[i] = Self[i + 1] then begin Result := i; exit; end; end; /// Находит первую пару подряд идущих одинаковых элементов, используя функцию сравнения eq, и возвращает индекс первого элемента пары. Если не найден, возвращается -1 function AdjacentFind(Self: IList; eq: (T,T)->boolean; start: integer := 0): integer; extensionmethod; begin Result := -1; for var i := start to Self.Count - 2 do if eq(Self[i], Self[i + 1]) then begin Result := i; exit; end; end; /// Возвращает индекс первого минимального элемента начиная с позиции index function IndexMin(Self: List; index: integer := 0): integer; extensionmethod; where T: IComparable; begin var min := Self[index]; Result := index; for var i := index + 1 to Self.Count - 1 do if Self[i].CompareTo(min) < 0 then begin Result := i; min := Self[i]; end; end; /// Возвращает индекс первого максимального элемента начиная с позиции index function IndexMax(Self: List; index: integer := 0): integer; extensionmethod; where T: System.IComparable; begin var max := Self[index]; Result := index; for var i := index + 1 to Self.Count - 1 do if Self[i].CompareTo(max) > 0 then begin Result := i; max := Self[i]; end; end; /// Возвращает индекс последнего минимального элемента в диапазоне [0,index-1] function LastIndexMin(Self: List; index: integer): integer; extensionmethod; where T: System.IComparable; begin var min := Self[index]; Result := index; for var i := index - 1 downto 0 do if Self[i].CompareTo(min) < 0 then begin Result := i; min := Self[i]; end; end; /// Возвращает индекс последнего минимального элемента function LastIndexMin(Self: List): integer; extensionmethod; where T: System.IComparable; begin Result := Self.LastIndexMin(Self.Count - 1); end; /// Возвращает индекс последнего минимального элемента в диапазоне [0,index-1] function LastIndexMax(Self: List; index: integer): integer; extensionmethod; where T: System.IComparable; begin var max := Self[index]; Result := index; for var i := index - 1 downto 0 do if Self[i].CompareTo(max) > 0 then begin Result := i; max := Self[i]; end; end; /// Возвращает индекс последнего максимального элемента function LastIndexMax(Self: List): integer; extensionmethod; where T: System.IComparable; begin Result := Self.LastIndexMax(Self.Count - 1); end; /// Возвращает индекс первого элемента с минимальным значением ключа function IndexMinBy(Self: array of T; keySelector: T -> TKey): integer; extensionmethod; begin if Self.Length = 0 then raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY); var minIndex := 0; var minKey := keySelector(Self[0]); var comp := Comparer&.Default; for var i := 1 to Self.Length - 1 do begin var currentKey := keySelector(Self[i]); if comp.Compare(currentKey,minKey) < 0 then begin minKey := currentKey; minIndex := i; end; end; Result := minIndex; end; /// Возвращает индекс первого элемента с максимальным значением ключа function IndexMaxBy(Self: array of T; keySelector: T -> TKey): integer; extensionmethod; begin if Self.Length = 0 then raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY); var maxIndex := 0; var maxKey := keySelector(Self[0]); var comp := Comparer&.Default; for var i := 1 to Self.Length - 1 do begin var currentKey := keySelector(Self[i]); if comp.Compare(currentKey,maxKey) > 0 then begin maxKey := currentKey; maxIndex := i; end; end; Result := maxIndex; end; /// Возвращает индекс последнего элемента с минимальным значением ключа function LastIndexMinBy(Self: array of T; keySelector: T -> TKey): integer; extensionmethod; begin if Self.Length = 0 then raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY); var minIndex := 0; var minKey := keySelector(Self[0]); var comp := Comparer&.Default; for var i := 1 to Self.Length - 1 do begin var currentKey := keySelector(Self[i]); if comp.Compare(currentKey,minKey) <= 0 then begin minKey := currentKey; minIndex := i; end; end; Result := minIndex; end; /// Возвращает индекс последнего элемента с максимальным значением ключа function LastIndexMaxBy(Self: array of T; keySelector: T -> TKey): integer; extensionmethod; begin if Self.Length = 0 then raise new System.ArgumentException(ARRAY_CANNOT_BE_EMPTY); var maxIndex := 0; var maxKey := keySelector(Self[0]); var comp := Comparer&.Default; for var i := 1 to Self.Length - 1 do begin var currentKey := keySelector(Self[i]); if comp.Compare(currentKey,maxKey) >= 0 then begin maxKey := currentKey; maxIndex := i; end; end; Result := maxIndex; end; /// Заменяет в массиве все вхождения одного значения на другое /// Заменяет в списке все вхождения одного значения на другое procedure Replace(Self: List; oldValue, newValue: T); extensionmethod; begin for var i := 0 to Self.Count - 1 do if Self[i] = oldValue then Self[i] := newValue; end; /// Преобразует элементы массива или списка по заданному правилу procedure Transform(Self: List; f: T->T); extensionmethod; begin for var i := 0 to Self.Count - 1 do Self[i] := f(Self[i]); end; /// Преобразует элементы массива или списка по заданному правилу procedure Transform(Self: List; f: (T,integer)->T); extensionmethod; begin for var i := 0 to Self.Count - 1 do Self[i] := f(Self[i],i); end; /// Заполняет элементы списка указанным значением procedure Fill(Self: List; x: T); extensionmethod; begin for var i := 0 to Self.Count - 1 do Self[i] := x; end; /// Заполняет элементы списка значениями, вычисляемыми по некоторому правилу procedure Fill(Self: List; f: integer->T); extensionmethod; begin for var i := 0 to Self.Count - 1 do Self[i] := f(i); end; ///-- function CreateSliceFromListInternal(Self: List; from, step, count: integer): List; begin Result := new List(count); var f := from; loop count do begin Result.Add(Self[f]); f += step; end; end; ///-- procedure CorrectCountForSlice(Len, from, step: integer; var count: integer); begin if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); if count < 0 then raise new System.ArgumentOutOfRangeException('count', count, GetTranslation(PARAMETER_MUST_BE_GREATER_EQUAL_0)); if (from < 0) or (from > Len - 1) then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); var cnt := step > 0 ? Len - from : from + 1; var cntstep := (cnt - 1) div abs(step) + 1; if count > cntstep then count := cntstep; end; ///-- function SliceListImpl(Self: List; from, step, count: integer): List; begin CorrectCountForSlice(Self.Count, from, step, count); Result := CreateSliceFromListInternal(Self, from, step, count); end; /// Возвращает срез списка от индекса from с шагом step function Slice(Self: List; from, step: integer): List; extensionmethod; begin Result := SliceListImpl(Self, from, step, integer.MaxValue); end; /// Возвращает срез списка от индекса from с шагом step длины не более count function Slice(Self: List; from, step, count: integer): List; extensionmethod; begin Result := SliceListImpl(Self, from, step, count); end; /// Удаляет последний элемент. Если элементов нет, генерирует исключение function RemoveLast(Self: List): List; extensionmethod; begin Self.RemoveAt(Self.Count - 1); Result := Self; end; procedure CorrectFromTo(situation: integer; Len: integer; var from, &to: integer; step: integer); begin if situation=0 then exit; if step > 0 then begin case situation of 1: from := 0; 2: &to := Len; 3: (from, &to) := (0, Len) end; end else begin case situation of 1: from := Len - 1; 2: &to := -1; 3: (from, &to) := (Len - 1, -1); end; end; end; ///-- function CorrectFromToAndCalcCountForSystemSliceQuestion(situation: integer; Len: integer; var from, &to: integer; step: integer): integer; begin if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); CorrectFromTo(situation, Len, from, &to, step); if step > 0 then begin if from < 0 then from += (step - from - 1) div step * step; // from может оказаться > Len - 1 var m := Min(Len,&to); if from >= m then Result := 0 else Result := (m - from - 1) div step + 1 end else begin if from > Len - 1 then from -= (from - Len - step) div step * step; // from может оказаться < 0 var m := Max(&to,-1); if from <= m then Result := 0 else Result := (from - m - 1) div (-step) + 1 end; end; ///-- function CheckAndCorrectFromToAndCalcCountForSystemSlice(situation: integer; Len: integer; var from, &to: integer; step: integer): integer; begin // situation = 0 - все параметры присутствуют // situation = 1 - from отсутствует // situation = 2 - to отсутствует // situation = 3 - from и to отсутствуют if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); if (situation = 0) or (situation = 2) then if (from < 0) or (from > Len - 1) then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); if (situation = 0) or (situation = 1) then if (&to < -1) or (&to > Len) then raise new ArgumentException(GetTranslation(PARAMETER_TO_OUT_OF_RANGE)); if situation > 0 then CorrectFromTo(situation, Len, from, &to, step); // s[a:b] - Opt if step = 1 then begin Result := &to - from; if Result<0 then Result := 0; exit; end; var count: integer; if step > 0 then begin var cnt := &to - from; if cnt <= 0 then count := 0 else count := (cnt - 1) div step + 1; end else begin var cnt := from - &to; if cnt <= 0 then count := 0 else count := (cnt - 1) div (-step) + 1; end; Result := count; end; ///-- (*procedure CheckStepAndCorrectFromTo(situation: integer; Len: integer; var from, &to: integer; step: integer); begin // situation = 0 - все параметры присутствуют // situation = 1 - from отсутствует // situation = 2 - to отсутствует // situation = 3 - from и to отсутствуют if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); {if (situation=0) or (situation=2) then if (from < 0) or (from > Len - 1) then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); if (situation=0) or (situation=1) then if (&to < -1) or (&to > Len) then raise new ArgumentException(GetTranslation(PARAMETER_TO_OUT_OF_RANGE));} CorrectFromTo(situation, Len, from, &to, step); end;*) ///-- function SystemSliceListImpl(Self: List; situation: integer; from, &to: integer; step: integer := 1): List; begin var count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, Self.Count, from, &to, step); if step=1 then Result := Self.GetRange(from,count) else Result := CreateSliceFromListInternal(Self, from, step, count); end; ///-- function SystemSlice(Self: List; situation: integer; from, &to: SystemIndex; step: integer := 1): List; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; Result := SystemSliceListImpl(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSlice(Self: List; situation: integer; from, &to: integer; step: integer := 1): List; extensionmethod; begin Result := SystemSliceListImpl(Self, situation, from, &to, step); end; ///-- procedure SystemSliceAssignmentListImpl(Self: List; rightValue: List; situation: integer; from, &to: integer; step: integer := 1); begin var count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, Self.Count, from, &to, step); if count <> rightValue.Count then raise new System.ArgumentException(GetTranslation(SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL)); var f := from; for var i:=0 to count-1 do begin Self[f] := rightValue[i]; f += step; end; end; ///-- procedure SystemSliceAssignment(Self: List; rightValue: List; situation: integer; from, &to: SystemIndex; step: integer := 1); extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; SystemSliceAssignmentListImpl(Self, rightValue, situation, from.IndexValue, &to.IndexValue, step); end; ///-- procedure SystemSliceAssignment(Self: List; rightValue: List; situation: integer; from, &to: integer; step: integer := 1); extensionmethod; begin SystemSliceAssignmentListImpl(Self, rightValue, situation, from, &to, step); end; ///-- function SystemSliceListImplQuestion(Self: List; situation: integer; from, &to: integer; step: integer := 1): List; begin var count := CorrectFromToAndCalcCountForSystemSliceQuestion(situation, Self.Count, from, &to, step); Result := CreateSliceFromListInternal(Self, from, step, count); end; ///-- function SystemSliceQuestion(Self: List; situation: integer; from, &to: SystemIndex; step: integer := 1): List; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; Result := SystemSliceListImplQuestion(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSliceQuestion(Self: List; situation: integer; from, &to: integer; step: integer := 1): List; extensionmethod; begin Result := SystemSliceListImplQuestion(Self, situation, from, &to, step); end; // ----------------------------------------------------- //>> Методы расширения двумерных динамических массивов # Extension methods for array [,] of T // ----------------------------------------------------- /// Количество строк в двумерном массиве function RowCount(Self: array [,] of T): integer; extensionmethod; begin Result := Self.GetLength(0); end; /// Количество столбцов в двумерном массиве function ColCount(Self: array [,] of T): integer; extensionmethod; begin Result := Self.GetLength(1); end; /// Количество столбцов в двумерном массиве function Size(Self: array [,] of T): (integer,integer); extensionmethod; begin Result := (Self.GetLength(0),Self.GetLength(1)); end; /// Есть ли элемент в матрице function operator in(x: T; a: array[,] of T): boolean; extensionmethod; begin var (m,n) := a.Size; Result := False; for var i:=0 to m-1 do for var j:=0 to n-1 do if a[i,j]=x then begin Result := True; exit; end; end; /// Равны ли матрицы function MatrEqual(Self,b: array[,] of T): boolean; extensionmethod := MatrEqual(Self,b); /// Вывод двумерного массива, w - ширина поля вывода function Print(Self: array [,] of T; w: integer := 4): array [,] of T; extensionmethod; begin for var i := 0 to Self.RowCount - 1 do begin for var j := 0 to Self.ColCount - 1 do begin if PrintMatrixWithFormat then Write(ObjectToString(Self[i, j]).PadLeft(w)) else Print(Self[i, j]); end; Writeln; end; Result := Self; end; /// Вывод двумерного вещественного массива по формату :w:f function Print(Self: array [,] of real; w: integer := 7; f: integer := 2): array [,] of real; extensionmethod; begin for var i := 0 to Self.RowCount - 1 do begin for var j := 0 to Self.ColCount - 1 do begin if PrintMatrixWithFormat then Write(FormatValue(Self[i, j], w, f)) else Print(Self[i, j]); end; Writeln; end; Result := Self; end; /// Вывод двумерного массива и переход на следующую строку, w - ширина поля вывода function Println(Self: array [,] of T; w: integer := 4): array [,] of T; extensionmethod; begin Self.Print(w); Result := Self; end; /// Вывод двумерного вещественного массива по формату :w:f и переход на следующую строку function Println(Self: array [,] of real; w: integer := 7; f: integer := 2): array [,] of real; extensionmethod; begin Self.Print(w, f); Result := Self; end; /// k-тая строка двумерного массива function Row(Self: array [,] of T; k: integer): array of T; extensionmethod; begin var n := Self.ColCount; var res := new T[n]; for var j := 0 to n - 1 do res[j] := Self[k, j]; Result := res; end; /// k-тый столбец двумерного массива function Col(Self: array [,] of T; k: integer): array of T; extensionmethod; begin var m := Self.RowCount; var res := new T[m]; for var i := 0 to m - 1 do res[i] := Self[i, k]; Result := res; end; /// k-тая строка двумерного массива как последовательность function RowSeq(Self: array [,] of T; k: integer): sequence of T; extensionmethod; begin for var j := 0 to Self.ColCount - 1 do yield Self[k, j]; end; /// k-тый столбец двумерного массива как последовательность function ColSeq(Self: array [,] of T; k: integer): sequence of T; extensionmethod; begin for var i := 0 to Self.RowCount - 1 do yield Self[i, k]; end; /// Возвращает массив строк двумерного массива function Rows(Self: array [,] of T): array of array of T; extensionmethod; type ArrT = array of T; begin var m := Self.RowCount; var n := Self.ColCount; var a := new ArrT[m]; for var i := 0 to m - 1 do a[i] := new T[n]; for var i := 0 to m - 1 do for var j := 0 to n - 1 do a[i][j] := Self[i,j]; Result := a; end; /// Возвращает массив столбцов двумерного массива function Cols(Self: array [,] of T): array of array of T; extensionmethod; type ArrT = array of T; begin var m := Self.RowCount; var n := Self.ColCount; var a := new ArrT[n]; for var j := 0 to n - 1 do a[j] := new T[m]; for var j := 0 to n - 1 do for var i := 0 to m - 1 do a[j][i] := Self[i,j]; Result := a; end; /// Возвращает последовательность строк двумерного массива function RowsSeq(Self: array [,] of T): sequence of sequence of T; extensionmethod; begin for var i := 0 to Self.RowCount - 1 do yield Self.RowSeq(i); end; /// Возвращает последовательность столбцов двумерного массива function ColsSeq(Self: array [,] of T): sequence of sequence of T; extensionmethod; begin for var j := 0 to Self.ColCount - 1 do yield Self.ColSeq(j); end; /// Меняет местами две строки двумерного массива с номерами k1 и k2 procedure SwapRows(Self: array [,] of T; k1, k2: integer); extensionmethod; begin for var j := 0 to Self.ColCount - 1 do Swap(Self[k1, j], Self[k2, j]) end; /// Меняет местами два столбца двумерного массива с номерами k1 и k2 procedure SwapCols(Self: array [,] of T; k1, k2: integer); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do Swap(Self[i, k1], Self[i, k2]) end; /// Меняет строку k двумерного массива на другую строку procedure SetRow(Self: array [,] of T; k: integer; a: array of T); extensionmethod; begin if a.Length <> Self.ColCount then raise new System.ArgumentException(GetTranslation(ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE)); for var j := 0 to Self.ColCount - 1 do Self[k, j] := a[j] end; /// Меняет строку k двумерного массива на другую строку procedure SetRow(Self: array [,] of T; k: integer; a: sequence of T); extensionmethod := Self.SetRow(k,a.ToArray); /// Меняет столбец k двумерного массива на другой столбец procedure SetCol(Self: array [,] of T; k: integer; a: array of T); extensionmethod; begin if a.Length <> Self.RowCount then raise new System.ArgumentException(GetTranslation(ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE)); for var i := 0 to Self.RowCount - 1 do Self[i, k] := a[i] end; /// Меняет столбец k двумерного массива на другой столбец procedure SetCol(Self: array [,] of T; k: integer; a: sequence of T); extensionmethod := Self.SetCol(k,a.ToArray); /// Возвращает по заданному двумерному массиву последовательность (a[i,j],i,j) function ElementsWithIndices(Self: array [,] of T): sequence of (T, integer, integer); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do yield (Self[i, j], i, j) end; /// Возвращает по заданному двумерному массиву последовательность индексов элементов, удовлетворяющих заданному условию function Indices(Self: array [,] of T; cond: T -> boolean): sequence of (integer, integer); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do if cond(Self[i,j]) then yield (i, j) end; /// Возвращает по заданному двумерному массиву последовательность индексов элементов, удовлетворяющих заданному условию function Indices(Self: array [,] of T; cond: (T,integer,integer) -> boolean): sequence of (integer, integer); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do if cond(Self[i,j],i,j) then yield (i, j) end; /// Возвращает по заданному двумерному массиву последовательность его элементов по строкам function ElementsByRow(Self: array [,] of T): sequence of T; extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do yield Self[i, j] end; /// Возвращает по заданному двумерному массиву последовательность его элементов по столбцам function ElementsByCol(Self: array [,] of T): sequence of T; extensionmethod; begin for var j := 0 to Self.ColCount - 1 do for var i := 0 to Self.RowCount - 1 do yield Self[i, j] end; /// Преобразует элементы двумерного массива и возвращает преобразованный массив function ConvertAll(Self: array [,] of T; converter: T->T1): array [,] of T1; extensionmethod; begin Result := new T1[Self.RowCount, Self.ColCount]; for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Result[i, j] := converter(Self[i, j]); end; /// Преобразует элементы двумерного массива и возвращает преобразованный массив function ConvertAll(Self: array [,] of T; converter: (T,integer,integer)->T1): array [,] of T1; extensionmethod; begin Result := new T1[Self.RowCount, Self.ColCount]; for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Result[i, j] := converter(Self[i, j],i,j); end; /// Преобразует элементы двумерного массива по заданному правилу procedure Transform(Self: array [,] of T; f: T->T); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Self[i, j] := f(Self[i, j]); end; /// Преобразует элементы двумерного массива по заданному правилу procedure Transform(Self: array [,] of T; f: (T,integer,integer)->T); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Self[i, j] := f(Self[i, j],i,j); end; /// Заполняет элементы двумерного массива значениями, вычисляемыми по некоторому правилу procedure Fill(Self: array [,] of T; f: (integer,integer) ->T); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Self[i, j] := f(i, j); end; /// Заполняет элементы двумерного массива случайными значениями в диапазоне от a до b procedure FillRandom(Self: array [,] of integer; a,b: integer); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Self[i, j] := Random(a,b); end; /// Заполняет элементы двумерного массива случайными значениями в диапазоне от a до b procedure FillRandom(Self: array [,] of real; a,b: real); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do Self[i, j] := a + Random*(b-a); end; /// Применяет действие к каждому элементу двумерного массива procedure &ForEach(Self: array [,] of T; act: T -> ()); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do act(Self[i, j]); end; /// Применяет действие к каждому элементу двумерного массива procedure &ForEach(Self: array [,] of T; act: (T,integer,integer) -> ()); extensionmethod; begin for var i := 0 to Self.RowCount - 1 do for var j := 0 to Self.ColCount - 1 do act(Self[i, j],i,j); end; function InR(Self: integer; a,b: integer): boolean; begin Result := (a <= Self) and (Self <= b); end; /// Возвращает срез двумерного массива. RowIndex и ColIndex задают срезаемые строки и столбцы function MatrSlice(Self: array[,] of T; RowIndex: array of integer; ColIndex: array of integer): array[,] of T; extensionmethod; begin if RowIndex = nil then raise new System.ArgumentNullException('RowIndex'); if ColIndex = nil then raise new System.ArgumentNullException('ColIndex'); if RowIndex.Any(i->not InR(i,0,Self.RowCount-1)) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_ROW_INDEX),new Exception); if ColIndex.Any(i->not InR(i,0,Self.ColCount-1)) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_COL_INDEX),new Exception); Result := new T[RowIndex.Length, ColIndex.Length]; var r := 0; foreach var ir in RowIndex do begin var c := 0; foreach var jc in ColIndex do begin Result[r, c] := Self[ir, jc]; c += 1; end; r += 1; end end; /// Возвращает срез двумерного массива между строками FromRow, ToRow и столбцами FromCol, ToCol function MatrSlice(Self: array[,] of T; FromRow, ToRow, FromCol, ToCol: integer): array[,] of T; extensionmethod; begin if not InR(FromRow,0,Self.RowCount-1) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_ROW_INDEX_FROM),new Exception); if not InR(ToRow,0,Self.RowCount-1) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_ROW_INDEX_TO),new Exception); if not InR(FromCol,0,Self.ColCount-1) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_COL_INDEX_FROM),new Exception); if not InR(ToCol,0,Self.ColCount-1) then raise new System.ArgumentOutOfRangeException(GetTranslation(BAD_COL_INDEX_TO),new Exception); Result := new T[ToRow-FromRow+1, ToCol-FromCol+1]; var r := 0; for var ir:=FromRow to ToRow do begin var c := 0; for var jc:=FromCol to ToCol do begin Result[r, c] := Self[ir, jc]; c += 1; end; r += 1; end end; // ----------------------------------------------------- //>> Фиктивная секция YYY - не удалять! # YYY // ----------------------------------------------------- function Matr(m,n: integer; params data: array of T): array [,] of T; begin if data.Length<>m*n then raise new System.ArgumentException(GetTranslation(INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT)); Result := new T[m, n]; var k := 0; for var i:=0 to Result.RowCount-1 do for var j:=0 to Result.ColCount-1 do begin Result[i,j] := data[k]; k += 1; end; end; function Matr(params aa: array of array of T): array [,] of T; begin var cols := aa.Max(a -> a.Length); var r := new T[aa.Length,cols]; for var i:=0 to aa.Length-1 do for var j:=0 to aa[i].Length-1 do r[i,j] := aa[i][j]; Result := r; end; /// Генерирует двумерный массив по массиву массивов строк function MatrByRow(a: array of array of T): array [,] of T; begin var m := a.Length; var n := if m = 0 then 0 else a.Max(aa -> aa.Length); var res := new T[m,n]; for var i := 0 to m - 1 do for var j := 0 to a[i].Length-1 do res[i,j] := a[i][j]; Result := res; end; /// Генерирует двумерный массив по последовательности массивов строк function MatrByRow(a: sequence of array of T): array [,] of T; begin var m := a.Count; var n := if m = 0 then 0 else a.Max(aa -> aa.Length); var res := new T[m,n]; var i := 0; foreach var aa in a do begin for var j := 0 to aa.Length-1 do res[i,j] := aa[j]; i += 1; end; Result := res; end; /// Генерирует двумерный массив по последовательности последовательностей строк function MatrByRow(a: sequence of sequence of T): array [,] of T; begin var m := a.Count; var n := if m = 0 then 0 else a.First.Count; var res := new T[m,n]; var i := 0; foreach var aa in a do begin var j := 0; foreach var x in aa do begin res[i,j] := x; j += 1; end; i += 1; end; Result := res; end; /// Генерирует двумерный массив по строкам из последовательности function MatrByRow(m,n: integer; a: sequence of T): array [,] of T; begin var res := new T[m,n]; var (i,j,num) := (0,0,0); foreach var x in a do begin if num >= m*n then break; res[i,j] := x; num += 1; j += 1; if j >= n then begin j := 0; i += 1; end; end; Result := res; end; /// Генерирует двумерный массив по массиву массивов столбцов function MatrByCol(a: array of array of T): array [,] of T; begin var n := a.Length; var m := if n = 0 then 0 else a.Select(aa -> aa.Length).Max; var res := new T[m,n]; for var j := 0 to n - 1 do for var i := 0 to a[j].Length-1 do res[i,j] := a[j][i]; Result := res; end; /// Генерирует двумерный массив по последовательности массивов столбцов function MatrByCol(a: sequence of array of T): array [,] of T; begin var n := a.Count; var m := if n = 0 then 0 else a.Select(aa -> aa.Length).Max; var res := new T[m,n]; var j := 0; foreach var aa in a do begin for var i := 0 to aa.Length-1 do res[i,j] := aa[i]; j += 1; end; Result := res; end; /// Генерирует двумерный массив по последовательности последовательностей столбцов function MatrByCol(a: sequence of sequence of T): array [,] of T; begin var n := a.Count; var m := if n = 0 then 0 else a.First.Count; var res := new T[m,n]; var j := 0; foreach var aa in a do begin var i := 0; foreach var x in aa do begin res[i,j] := x; i += 1; end; j += 1; end; Result := res; end; /// Генерирует двумерный массив по столбцам из последовательности function MatrByCol(m,n: integer; a: sequence of T): array [,] of T; begin var res := new T[m,n]; var (i,j,num) := (0,0,0); foreach var x in a do begin if num >= m*n then break; res[i,j] := x; num += 1; i += 1; if i >= m then begin i := 0; j += 1; end; end; Result := res; end; // Реализация операций с матрицами - только после введения RowCount и ColCount function MatrRandom(m: integer; n: integer; a, b: integer): array [,] of integer; begin Result := new integer[m, n]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := Random(a, b); end; function MatrRandomInteger(m: integer; n: integer; a, b: integer): array [,] of integer; begin Result := new integer[m, n]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := Random(a, b); end; function MatrRandomReal(m: integer; n: integer; a, b: real; digits: integer): array [,] of real; begin Result := new real[m, n]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := RandomReal(a,b,digits); end; function MatrFill(m, n: integer; x: T): array [,] of T; begin Result := new T[m, n]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := x; end; function MatrGen(m, n: integer; gen: (integer,integer)->T): array [,] of T; begin Result := new T[m, n]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := gen(i, j); end; function Transpose(a: array [,] of T): array [,] of T; begin var m := a.RowCount; var n := a.ColCount; Result := new T[n, m]; for var i := 0 to Result.RowCount - 1 do for var j := 0 to Result.ColCount - 1 do Result[i, j] := a[j, i] end; function ReadMatrInteger(m, n: integer): array [,] of integer; begin Result := new integer[m, n]; for var i := 0 to m - 1 do for var j := 0 to n - 1 do Result[i, j] := ReadInteger; end; function ReadMatrReal(m, n: integer): array [,] of real; begin Result := new real[m, n]; for var i := 0 to m - 1 do for var j := 0 to n - 1 do Result[i, j] := ReadReal; end; function MatrEqual(a, b: array [,] of T): boolean; begin var (m1,n1) := a.Size; var (m2,n2) := b.Size; Result := True; if (m1<>m2) or (n1<>n2) then Result := False else for var i:=0 to m1-1 do for var j:=0 to n1-1 do if a[i,j]<>b[i,j] then begin Result := False; exit; end; end; // ----------------------------------------------------- //>> Методы расширения одномерных динамических массивов # Extension methods for array of T // ----------------------------------------------------- // Дополнения февраль 2016: Shuffle, AdjacentFind, IndexMin, IndexMax, Replace, Transform // Статические методы - в методы расширения: BinarySearch, ConvertAll, Find, FindIndex, FindAll, // FindLast, FindLastIndex, IndexOf, Contains, LastIndexOf, Reverse, Sort // Дополнения март 2020: RandomElement, FillRandom // Дополнения май 2020: Combinations, Permutations /// Возвращает, совпадают ли массивы function ArrEqual(Self,b: array of T): boolean; extensionmethod := ArrEqual(Self,b); /// Заполняет массив случайными значениями в диапазоне от a до b procedure FillRandom(Self: array of integer; a,b: integer); extensionmethod; begin for var i:=0 to Self.Length-1 do Self[i] := Random(a,b); end; /// Заполняет массив случайными значениями в диапазоне от a до b procedure FillRandom(Self: array of real; a,b: real); extensionmethod; begin for var i:=0 to Self.Length-1 do Self[i] := a + Random*(b-a); end; /// Возвращает случайный элемент массива function RandomElement(Self: array of T): T; extensionmethod; begin Result := Self[Random(Self.Length)]; end; /// Перемешивает элементы массива случайным образом function Shuffle(Self: array of T): array of T; extensionmethod; begin for var i := Self.Length - 1 downto 1 do Swap(Self[i], Self[Random(i + 1)]); Result := Self; end; {/// Находит первую пару подряд идущих одинаковых элементов и возвращает индекс первого элемента пары. Если не найден, возвращается -1 function AdjacentFind(Self: array of T; start: integer := 0): integer; extensionmethod; begin Result := -1; for var i:=start to Self.Length-2 do if Self[i]=Self[i+1] then begin Result := i; exit; end; end; /// Находит первую пару подряд идущих одинаковых элементов, используя функцию сравнения eq, и возвращает индекс первого элемента пары. Если не найден, возвращается -1 function AdjacentFind(Self: array of T; eq: (T,T)->boolean; start: integer := 0): integer; extensionmethod; begin Result := -1; for var i:=start to Self.Length-2 do if eq(Self[i],Self[i+1]) then begin Result := i; exit; end; end;} /// Возвращает минимальный элемент function Min(Self: array of T): T; extensionmethod; where T: System.IComparable; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i].CompareTo(Result) < 0 then Result := Self[i]; end; /// Возвращает максимальный элемент function Max(Self: array of T): T; extensionmethod; where T: System.IComparable; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i].CompareTo(Result) > 0 then Result := Self[i]; end; /// Возвращает минимальный элемент function Min(Self: array of integer): integer; extensionmethod; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i] < Result then Result := Self[i]; end; /// Возвращает минимальный элемент function Min(Self: array of real): real; extensionmethod; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i] < Result then Result := Self[i]; end; /// Возвращает максимальный элемент function Max(Self: array of integer): integer; extensionmethod; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i] > Result then Result := Self[i]; end; /// Возвращает максимальный элемент function Max(Self: array of real): real; extensionmethod; begin Result := Self[0]; for var i := 1 to Self.Length - 1 do if Self[i] > Result then Result := Self[i]; end; /// Возвращает индекс первого минимального элемента function IndexMin(Self: array of T; index: integer := 0): integer; extensionmethod; where T: IComparable; begin var min := Self[index]; Result := index; for var i := index + 1 to Self.Count - 1 do if Self[i].CompareTo(min) < 0 then begin Result := i; min := Self[i]; end; end; /// Возвращает индекс первого максимального элемента function IndexMax(Self: array of T; index: integer := 0): integer; extensionmethod; where T: System.IComparable; begin var max := Self[index]; Result := index; for var i := index + 1 to Self.Count - 1 do if Self[i].CompareTo(max) > 0 then begin Result := i; max := Self[i]; end; end; /// Возвращает индекс последнего минимального элемента в диапазоне [0,index-1] function LastIndexMin(Self: array of T; index: integer): integer; extensionmethod; where T: System.IComparable; begin var min := Self[index]; Result := index; for var i := index - 1 downto 0 do if Self[i].CompareTo(min) < 0 then begin Result := i; min := Self[i]; end; end; /// Возвращает индекс последнего минимального элемента function LastIndexMin(Self: array of T): integer; extensionmethod; where T: System.IComparable; begin Result := Self.LastIndexMin(Self.Length - 1); end; /// Возвращает индекс последнего минимального элемента в диапазоне [0,index-1] function LastIndexMax(Self: array of T; index: integer): integer; extensionmethod; where T: System.IComparable; begin var max := Self[index]; Result := index; for var i := index - 1 downto 0 do if Self[i].CompareTo(max) > 0 then begin Result := i; max := Self[i]; end; end; /// Возвращает индекс последнего максимального элемента function LastIndexMax(Self: array of T): integer; extensionmethod; where T: System.IComparable; begin Result := Self.LastIndexMax(Self.Length - 1); end; /// Заполняет элементы массива указанным значением procedure Fill(Self: array of T; x: T); extensionmethod; begin for var i := 0 to Self.Length - 1 do Self[i] := x; end; /// Заполняет элементы массива значениями, вычисляемыми по некоторому правилу procedure Fill(Self: array of T; f: integer->T); extensionmethod; begin for var i := 0 to Self.Length - 1 do Self[i] := f(i); end; procedure Replace(Self: array of T; oldValue, newValue: T); extensionmethod; begin for var i := 0 to Self.Length - 1 do if Self[i] = oldValue then Self[i] := newValue; end; /// Преобразует элементы массива по заданному правилу procedure Transform(Self: array of T; f: T->T); extensionmethod; begin for var i := 0 to Self.Length - 1 do Self[i] := f(Self[i]); end; /// Преобразует элементы массива по заданному правилу procedure Transform(Self: array of T; f: (T,integer)->T); extensionmethod; begin for var i := 0 to Self.Length - 1 do Self[i] := f(Self[i],i); end; /// Выполняет бинарный поиск в отсортированном массиве function BinarySearch(Self: array of T; x: T): integer; extensionmethod; begin Result := System.Array.BinarySearch(self, x); end; /// Преобразует элементы массива и возвращает преобразованный массив function ConvertAll(Self: array of T; converter: T->T1): array of T1; extensionmethod; begin Result := System.Array.ConvertAll(self, t -> converter(t)); end; /// Преобразует элементы массива и возвращает преобразованный массив function ConvertAll(Self: array of T; converter: (T,integer)->T1): array of T1; extensionmethod; begin Result := new T1[Self.Length]; for var i := 0 to Self.Length - 1 do Result[i] := converter(Self[i],i); end; /// Выполняет поиск первого элемента в массиве, удовлетворяющего предикату. Если не найден, возвращается нулевое значение соответствующего типа function Find(Self: array of T; p: T->boolean): T; extensionmethod; begin Result := System.Array.Find(self, p); end; /// Выполняет поиск индекса первого элемента в массиве, удовлетворяющего предикату. Если не найден, возвращается -1 function FindIndex(Self: array of T; p: T->boolean): integer; extensionmethod; begin Result := System.Array.FindIndex(self, p); end; /// Выполняет поиск индекса первого элемента в массиве, удовлетворяющего предикату, начиная с индекса start. Если не найден, возвращается -1 function FindIndex(Self: array of T; start: integer; p: T->boolean): integer; extensionmethod; begin Result := System.Array.FindIndex(self, start, p); end; /// Возвращает в виде массива все элементы, удовлетворяющие предикату function FindAll(Self: array of T; p: T->boolean): array of T; extensionmethod; begin Result := System.Array.FindAll(self, p); end; /// Выполняет поиск последнего элемента в массиве, удовлетворяющего предикату. Если не найден, возвращается нулевое значение соответствующего типа function FindLast(Self: array of T; p: T->boolean): T; extensionmethod; begin Result := System.Array.FindLast(self, p); end; /// Выполняет поиск индекса последнего элемента в массиве, удовлетворяющего предикату. Если не найден, возвращается -1 function FindLastIndex(Self: array of T; p: T->boolean): integer; extensionmethod; begin Result := System.Array.FindLastIndex(self, p); end; /// Выполняет поиск индекса последнего элемента в массиве, удовлетворяющего предикату, в диапазоне индексов от 0 до start. Если не найден, возвращается -1 function FindLastIndex(self: array of T; start: integer; p: T->boolean): integer; extensionmethod; begin Result := System.Array.FindLastIndex(Self, start, p); end; /// Возвращает индекс первого вхождения элемента или -1 если элемент не найден function IndexOf(Self: array of T; x: T): integer; extensionmethod; begin Result := System.Array.IndexOf(Self, x); end; /// Возвращает индекс первого вхождения элемента начиная с индекса start или -1 если элемент не найден function IndexOf(Self: array of T; x: T; start: integer): integer; extensionmethod; begin Result := System.Array.IndexOf(Self, x, start); end; /// Возвращает индекс последнего вхождения элемента или -1 если элемент не найден function LastIndexOf(Self: array of T; x: T): integer; extensionmethod; begin Result := System.Array.LastIndexOf(Self, x); end; /// Возвращает индекс последнего вхождения элемента начиная с индекса start или -1 если элемент не найден function LastIndexOf(Self: array of T; x: T; start: integer): integer; extensionmethod; begin Result := System.Array.LastIndexOf(Self, x, start); end; /// Сортирует массив по возрастанию procedure Sort(Self: array of T); extensionmethod; begin System.Array.Sort(Self); end; /// Сортирует массив по возрастанию procedure Sort(Self: array of string); extensionmethod; begin System.Array.Sort(Self,System.StringComparer.Ordinal); end; /// Сортирует массив по убыванию procedure SortDescending(Self: array of T); extensionmethod; begin System.Array.Sort(Self); Reverse(Self); end; /// Сортирует массив по убыванию procedure SortDescending(Self: array of string); extensionmethod; begin System.Array.Sort(Self,System.StringComparer.Ordinal); Reverse(Self); end; /// Сортирует массив по возрастанию, используя cmp в качестве функции сравнения элементов procedure Sort(Self: array of T; cmp: (T,T) ->integer); extensionmethod; begin System.Array.Sort(Self, cmp); end; /// Сортирует массив по возрастанию по ключу procedure Sort(Self: array of T; keySelector: T -> T1); extensionmethod; begin var a := Self.OrderBy(keySelector).ToArray; System.Array.Copy(a,Self,a.Length); end; /// Сортирует массив по возрастанию по ключу procedure Sort(Self: array of T; keySelector: T -> string); extensionmethod; begin var a := Self.OrderBy(keySelector,System.StringComparer.Ordinal).ToArray; System.Array.Copy(a,Self,a.Length); end; /// Сортирует массив по убыванию по ключу procedure SortDescending(Self: array of T; keySelector: T -> T1); extensionmethod; begin var a := Self.OrderByDescending(keySelector).ToArray; System.Array.Copy(a,Self,a.Length); end; /// Сортирует массив по убыванию по ключу procedure SortDescending(Self: array of T; keySelector: T -> string); extensionmethod; begin var a := Self.OrderByDescending(keySelector,System.StringComparer.Ordinal).ToArray; System.Array.Copy(a,Self,a.Length); end; /// Возвращает индекс последнего элемента массива function High(Self: System.Array); extensionmethod := High(Self); /// Возвращает индекс первого элемента массива function Low(Self: System.Array); extensionmethod := Low(Self); /// Проверяет, отсортирован ли массив по возрастанию ключа function IsOrderedBy(self: array of T; keySelector: T -> TKey): boolean; extensionmethod; where TKey: System.IComparable; begin for var i := 0 to self.High - 1 do if keySelector(self[i]).CompareTo(keySelector(self[i + 1])) > 0 then exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по возрастанию ключа с компаратором function IsOrderedBy(self: array of T; keySelector: T -> TKey; comparer: IComparer): boolean; extensionmethod; begin for var i := 0 to self.High - 1 do if comparer.Compare(keySelector(self[i]), keySelector(self[i + 1])) > 0 then exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по убыванию ключа function IsOrderedByDescending(self: array of T; keySelector: T -> TKey): boolean; extensionmethod; where TKey: System.IComparable; begin for var i := 0 to self.High - 1 do if keySelector(self[i]).CompareTo(keySelector(self[i + 1])) < 0 then // Обратный знак exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по убыванию ключа с компаратором function IsOrderedByDescending(self: array of T; keySelector: T -> TKey; comparer: IComparer): boolean; extensionmethod; begin for var i := 0 to self.High - 1 do if comparer.Compare(keySelector(self[i]), keySelector(self[i + 1])) < 0 then // Обратный знак exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по возрастанию function IsOrdered(self: array of T): boolean; extensionmethod; where T: System.IComparable; begin for var i := 0 to self.High - 1 do if self[i].CompareTo(self[i + 1]) > 0 then exit(False); Result := True; end; /// Проверяет, отсортирован ли массив в порядке, заданном компаратором comparer function IsOrdered(self: array of T; comparer: IComparer): boolean; extensionmethod; begin for var i := 0 to self.High - 1 do if comparer.Compare(self[i], self[i + 1]) > 0 then exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по убыванию function IsOrderedDescending(self: array of T): boolean; extensionmethod; where T: System.IComparable; begin for var i := 0 to self.High - 1 do if self[i].CompareTo(self[i + 1]) < 0 then exit(False); Result := True; end; /// Проверяет, отсортирован ли массив по убыванию в порядке, заданном компаратором comparer function IsOrderedDescending(self: array of T; comparer: IComparer): boolean; extensionmethod; begin for var i := 0 to self.High - 1 do if comparer.Compare(self[i], self[i + 1]) < 0 then // Обратный знак exit(False); Result := True; end; /// Возвращает последовательность индексов одномерного массива function Indices(Self: array of T): sequence of integer; extensionmethod := Range(0, Self.Length - 1); /// Возвращает последовательность индексов элементов одномерного массива, удовлетворяющих условию function Indices(Self: array of T; cond: T->boolean): sequence of integer; extensionmethod; begin for var i := 0 to Self.High do if cond(Self[i]) then yield i; end; /// Возвращает последовательность индексов элементов одномерного массива, удовлетворяющих условию function Indices(Self: array of T; cond: (T,integer) ->boolean): sequence of integer; extensionmethod; begin for var i := 0 to Self.High do if cond(Self[i], i) then yield i; end; function NextCombHelper(ind: array of integer; m,n: integer): boolean; begin for var i:=m-1 downto 0 do if ind[i] < n - m + i then begin ind[i] += 1; for var j:=i to m-1 do ind[j+1] := ind[j] + 1; Result := True; exit end; Result := False; end; /// Возвращает все сочетания по m элементов function Combinations(Self: array of T; m: integer): sequence of array of T; extensionmethod; begin var res := new T[m]; var a := Self; var n := a.Length; var ind := Arr(0..n-1); repeat for var i:=0 to m-1 do res[i] := a[ind[i]]; yield Arr(res); until not NextCombHelper(ind,m,n); end; /// Возвращает все сочетания по m элементов function Combinations(Self: sequence of T; m: integer): sequence of array of T; extensionmethod; begin Result := Self.ToArray.Combinations(m); end; // Возвращает все сочетания по 2 элемента в виде кортежей {function Combinations2(Self: array of T): sequence of (T,T); extensionmethod; begin var a := Self; for var i:=0 to a.High-1 do for var j:=i+1 to a.High do yield (a[i],a[j]); end;} function NextPermutation(a: array of integer): boolean; begin var n := a.Length; var j := n - 2; while (j <> -1) and (a[j] >= a[j + 1]) do j -= 1; if j = -1 then begin Result := False; exit; end; var k := n - 1; while a[j] >= a[k] do k -= 1; Swap(a[j], a[k]); Reverse(a,j+1,n-1-j); Result := True; end; /// Возвращает все перестановки множества элементов, заданного массивом function Permutations(Self: array of T): sequence of array of T; extensionmethod; begin var a := Self; var n := a.Length; var res := new T[n]; var ind := Arr(0..n-1); repeat for var i:=0 to n-1 do res[i] := a[ind[i]]; yield Arr(res); until not NextPermutation(ind); end; /// Возвращает все перестановки множества элементов, заданного последовательностью function Permutations(Self: sequence of T): sequence of array of T; extensionmethod; begin Result := Self.ToArray.Permutations end; /// Возвращает все частичные перестановки из n элементов по m function Permutations(Self: array of T; m: integer): sequence of array of T; extensionmethod; begin Result := Self.Combinations(m).SelectMany(c->c.Permutations); end; /// Возвращает все частичные перестановки из n элементов по m function Permutations(Self: sequence of T; m: integer): sequence of array of T; extensionmethod; begin Result := Self.ToArray.Permutations(m); end; /// Возвращает n-тую декартову степень множества элементов, заданного массивом function CartesianPower(Self: array of T; n: integer): sequence of array of T; extensionmethod; begin var r := new integer[n]; var ar1 := new T[n]; for var i:=0 to n-1 do ar1[i] := Self[r[i]]; yield ar1; var m := Self.Length; while True do begin var i := n-1; r[i] += 1; while r[i]>=m do begin r[i] := 0; i -= 1; if i<0 then exit; r[i] += 1; end; var ar := new T[n]; for var j:=0 to n-1 do ar[j] := Self[r[j]]; yield ar; end; end; /// Возвращает n-тую декартову степень множества элементов, заданного последовательностью function CartesianPower(Self: sequence of T; n: integer): sequence of array of T; extensionmethod; begin Result := Self.ToArray.CartesianPower(n); end; // Не убирать этот комментарий! Нужен для корректного Intellisense ///-(расширение sequence of T) function Cartesian(b: sequence of T1): sequence of (T, T1); /// Возвращает декартово произведение последовательностей в виде последовательности пар function Cartesian(Self: array of T; n: integer): sequence of array of T; extensionmethod := Self.CartesianPower(n); ///-- function Cartesian(Self: sequence of T; n: integer): sequence of array of T; extensionmethod; begin Result := Self.ToArray.CartesianPower(n); end; /// Возвращает все перестановки букв в строке в виде последовательности строк function Permutations(Self: string): sequence of string; extensionmethod := Self.ToCharArray.Permutations.Select(p -> new string(p)); /// Возвращает все частичные перестановки букв строки по m символов в виде последовательности строк function Permutations(Self: string; m: integer): sequence of string; extensionmethod := Self.ToCharArray.Permutations(m).Select(p -> new string(p)); // Не убирать этот комментарий! Нужен для корректного Intellisense ///-(расширение sequence of T) function Cartesian(b: sequence of T1): sequence of (T, T1); /// Возвращает n-тую декартову степень множества символов, заданного строкой function Cartesian(Self: string; n: integer): sequence of string; extensionmethod := Self.ToCharArray.Cartesian(n).Select(p -> new string(p)); /// Возвращает n-тую декартову степень множества символов, заданного строкой function CartesianPower(Self: string; n: integer): sequence of string; extensionmethod := Self.ToCharArray.Cartesian(n).Select(p -> new string(p)); /// Возвращает все сочетания по m элементов function Combinations(Self: string; m: integer): sequence of string; extensionmethod := Self.ToCharArray.Combinations(m).Select(p -> new string(p)); // Внутренние функции для одномерных массивов ///-- function CreateSliceFromArrayInternal(Self: array of T; from, step, count: integer): array of T; begin Result := new T[count]; var f := from; for var i := 0 to count - 1 do begin Result[i] := Self[f]; f += step; end; end; ///-- function SliceArrayImpl(Self: array of T; from, step, count: integer): array of T; begin {if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); if (from < 0) or (from > Self.Length - 1) then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); var cnt := step > 0 ? Self.Length - from : from + 1; var cntstep := (cnt-1) div abs(step) + 1; if count > cntstep then count := cntstep;} CorrectCountForSlice(Self.Length, from, step, count); Result := CreateSliceFromArrayInternal(Self, from, step, count) end; /// Возвращает срез массива от индекса from с шагом step function Slice(Self: array of T; from, step: integer): array of T; extensionmethod; begin Result := SliceArrayImpl(Self, from, step, integer.MaxValue); end; /// Возвращает срез массива от индекса from с шагом step длины не более count function Slice(Self: array of T; from, step, count: integer): array of T; extensionmethod; begin Result := SliceArrayImpl(Self, from, step, count); end; ///-- function SystemSliceArrayImpl(Self: array of T; situation: integer; from, &to: integer; step: integer := 1): array of T; begin var count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, Self.Length, from, &to, step); {if (step = 1) and (count>32) then // 32 - empirical begin Result := new T[count]; System.Array.Copy(Self,from,Result,0,count); end else} Result := CreateSliceFromArrayInternal(Self, from, step, count) end; ///-- function SystemSlice(Self: array of T; situation: integer; from, &to: SystemIndex; step: integer := 1): array of T; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; Result := SystemSliceArrayImpl(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSlice(Self: array of T; situation: integer; from, &to: integer; step: integer := 1): array of T; extensionmethod; begin Result := SystemSliceArrayImpl(Self, situation, from, &to, step); end; ///-- procedure SystemSliceAssignmentArrayImpl(Self: array of T; rightValue: array of T; situation: integer; from, &to: integer; step: integer := 1); begin var count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, Self.Length, from, &to, step); if count <> rightValue.Length then raise new System.ArgumentException(GetTranslation(SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL)); var f := from; var i := 0; loop count do begin Self[f] := rightValue[i]; f += step; i += 1; end; end; ///-- procedure SystemSliceAssignment(Self: array of T; rightValue: array of T; situation: integer; from, &to: SystemIndex; step: integer := 1); extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; SystemSliceAssignmentArrayImpl(Self, rightValue, situation, from.IndexValue, &to.IndexValue, step); end; ///-- procedure SystemSliceAssignment(Self: array of T; rightValue: array of T; situation: integer; from, &to: integer; step: integer := 1); extensionmethod; begin SystemSliceAssignmentArrayImpl(Self, rightValue, situation, from, &to, step); end; ///-- function SystemSliceArrayImplQuestion(Self: array of T; situation: integer; from, &to: integer; step: integer := 1): array of T; begin var count := CorrectFromToAndCalcCountForSystemSliceQuestion(situation, Self.Length, from, &to, step); Result := CreateSliceFromArrayInternal(Self, from, step, count); end; ///-- function SystemSliceQuestion(Self: array of T; situation: integer; from, &to: SystemIndex; step: integer := 1): array of T; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; Result := SystemSliceArrayImplQuestion(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSliceQuestion(Self: array of T; situation: integer; from, &to: integer; step: integer := 1): array of T; extensionmethod; begin Result := SystemSliceArrayImplQuestion(Self, situation, from, &to, step); end; // Срезы многомерных массивов - вспомогательные типы и функции type SliceType = class situation,from, &to, step, count: integer; fromInverted, toInverted: boolean; function oneelem: boolean := step = integer.MaxValue; // если шаг = integer.MaxValue, то это один элемент, а не срез (договорённость) constructor (sit,f,t: integer; st: integer := 1); begin situation := sit; from := f; &to := t; fromInverted := False; toInverted := False; step := st; count := -1; // заполняется во внешней функции CorrectSliceAndCalcCount при известной длине по данной размерности //oneelem := step = integer.MaxValue; // если шаг = integer.MaxValue, то это один элемент, а не срез (договорённость) end; procedure CorrectSliceAndCalcCount(len: integer); begin if fromInverted then // Надеюсь, что ровно здесь. Это означает, что эти значения точно не пропущены from := len - from; if toInverted then &to := len - &to; if oneelem then count := 1 else count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, len, from, &to, step); end; static function operator implicit(i: integer): SliceType; static function operator implicit(ir: IntRange): SliceType; static function operator implicit(sl: (integer,integer,integer)): SliceType; static function operator implicit(sl: (SystemIndex,SystemIndex,integer)): SliceType; // a[^1:,^2] static function operator implicit(sl: (integer,SystemIndex,integer)): SliceType; // a[^1:,^2] static function operator implicit(sl: (SystemIndex,integer,integer)): SliceType; // a[^1:,^2] end; function Diap(f, t: integer) := new SliceType(0, f, t, 1); function Elem(ind: integer) := new SliceType(0, ind, ind+1, integer.MaxValue); function Slice(f, t: integer; st: integer := 1): SliceType; begin var sit := 0; if f = integer.MaxValue then sit += 1; if t = integer.MaxValue then sit += 2; Result := new SliceType(sit, f, t, st); end; {function Slice(f, t: SystemIndex; st: integer := 1): SliceType; begin Result := Slice(f.IndexValue, t.IndexValue, st); Result.fromInverted := f.IsInverted; Result.toInverted := t.IsInverted; end;} static function SliceType.operator implicit(i: integer): SliceType; begin Result := Elem(i); end; static function SliceType.operator implicit(ir: IntRange): SliceType; begin Result := Diap(ir.Low,ir.High); end; static function SliceType.operator implicit(sl: (integer,integer,integer)): SliceType; begin Result := Slice(sl[0],sl[1],sl[2]); end; static function SliceType.operator implicit(sl: (SystemIndex,SystemIndex,integer)): SliceType; begin Result := Slice(sl[0].IndexValue,sl[1].IndexValue,sl[2]); Result.fromInverted := sl[0].IsInverted; Result.toInverted := sl[1].IsInverted; end; static function SliceType.operator implicit(sl: (integer,SystemIndex,integer)): SliceType; begin Result := Slice(sl[0],sl[1].IndexValue,sl[2]); Result.toInverted := sl[1].IsInverted; end; static function SliceType.operator implicit(sl: (SystemIndex,integer,integer)): SliceType; begin Result := Slice(sl[0].IndexValue,sl[1],sl[2]); Result.fromInverted := sl[0].IsInverted; end; function ToOneDim(a: array [,] of T; l: array of SliceType): array of T; begin for var i:=0 to l.Length-1 do l[i].CorrectSliceAndCalcCount(a.GetLength(i)); var onedimsz := l[0].count * l[1].count; var res := new T[onedimsz]; if onedimsz>0 then begin var cur := 0; var i0 := l[0].from; loop l[0].count do begin var i1:=l[1].from; loop l[1].count do begin res[cur] := a[i0,i1]; cur += 1; i1 += l[1].step; end; i0 += l[0].step; end; end; Result := res; end; function ToOneDim(a: array [,,] of T; l: array of SliceType): array of T; begin for var i:=0 to l.Length-1 do l[i].CorrectSliceAndCalcCount(a.GetLength(i)); var onedimsz := l[0].count * l[1].count * l[2].count; var res := new T[onedimsz]; if onedimsz>0 then begin var cur := 0; var i0 := l[0].from; loop l[0].count do begin var i1:=l[1].from; loop l[1].count do begin var i2 := l[2].from; loop l[2].count do begin res[cur] := a[i0,i1,i2]; cur += 1; i2 += l[2].step; end; i1 += l[1].step; end; i0 += l[0].step; end; end; Result := res; end; function ToOneDim(a: array [,,,] of T; l: array of SliceType): array of T; begin for var i:=0 to l.Length-1 do l[i].CorrectSliceAndCalcCount(a.GetLength(i)); var onedimsz := l[0].count * l[1].count * l[2].count * l[3].count; var res := new T[onedimsz]; if onedimsz>0 then begin var cur := 0; var i0 := l[0].from; loop l[0].count do begin var i1:=l[1].from; loop l[1].count do begin var i2 := l[2].from; loop l[2].count do begin var i3 := l[3].from; loop l[3].count do begin res[cur] := a[i0,i1,i2,i3]; cur += 1; i3 += l[3].step; end; i2 += l[2].step; end; i1 += l[1].step; end; i0 += l[0].step; end; end; Result := res; end; function FromOneDim2(r: array of T; l: array of SliceType): array [,] of T; begin var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count); var cur := 0; var res := new T[dims[0],dims[1]]; for var i0:=0 to dims[0]-1 do for var i1:=0 to dims[1]-1 do begin res[i0,i1] := r[cur]; cur += 1; end; Result := res; end; function FromOneDim3(r: array of T; l: array of SliceType): array [,,] of T; begin var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count); var cur := 0; var res := new T[dims[0],dims[1],dims[2]]; for var i0:=0 to dims[0]-1 do for var i1:=0 to dims[1]-1 do for var i2:=0 to dims[2]-1 do begin res[i0,i1,i2] := r[cur]; cur += 1; end; Result := res; end; function FromOneDim4(r: array of T; l: array of SliceType): array [,,,] of T; begin var dims := l.FindAll(x -> x.oneelem = False).ConvertAll(x -> x.count); var cur := 0; var res := new T[dims[0],dims[1],dims[2],dims[3]]; for var i0:=0 to dims[0]-1 do for var i1:=0 to dims[1]-1 do for var i2:=0 to dims[2]-1 do for var i3:=0 to dims[3]-1 do begin res[i0,i1,i2,i3] := r[cur]; cur += 1; end; Result := res; end; function FromOneDimN(r: array of T; l: array of SliceType): System.Array; begin var rank := l.Count(x -> x.oneelem = False); case rank of 1: Result := r; 2: Result := FromOneDim2(r,l); 3: Result := FromOneDim3(r,l); 4: Result := FromOneDim4(r,l); end; end; function SliceN(a: array[,] of T; l: array of SliceType): System.Array; begin var r := ToOneDim(a,l); Result := FromOneDimN(r,l); end; function SliceN(a: array[,,] of T; l: array of SliceType): System.Array; begin var r := ToOneDim(a,l); Result := FromOneDimN(r,l); end; function SliceN(a: array[,,,] of T; l: array of SliceType): System.Array; begin var r := ToOneDim(a,l); Result := FromOneDimN(r,l); end; {type // это не компилируется в PABCSystem ArrT = array of T; Arr2T = array [,] of T; Arr3T = array [,,] of T; Arr4T = array [,,,] of T;} ///-- function SystemSliceN1(Self: array[,] of T; params l: array of SliceType): array of T; extensionmethod := SliceN(Self,l) as array of T; ///-- function SystemSliceN1(Self: array[,,] of T; params l: array of SliceType): array of T; extensionmethod := SliceN(Self,l) as array of T; ///-- function SystemSliceN1(Self: array[,,,] of T; params l: array of SliceType): array of T; extensionmethod := SliceN(Self,l) as array of T; ///-- function SystemSliceN2(Self: array[,] of T; params l: array of SliceType): array[,] of T; extensionmethod := SliceN(Self,l) as array [,] of T; ///-- function SystemSliceN2(Self: array[,,] of T; params l: array of SliceType): array[,] of T; extensionmethod := SliceN(Self,l) as array [,] of T; ///-- function SystemSliceN2(Self: array[,,,] of T; params l: array of SliceType): array[,] of T; extensionmethod := SliceN(Self,l) as array [,] of T; ///-- function SystemSliceN3(Self: array[,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod := SliceN(Self,l) as array [,,] of T; ///-- function SystemSliceN3(Self: array[,,,] of T; params l: array of SliceType): array[,,] of T; extensionmethod := SliceN(Self,l) as array [,,] of T; ///-- function SystemSliceN4(Self: array[,,,] of T; params l: array of SliceType): array[,,,] of T; extensionmethod := SliceN(Self,l) as array [,,,] of T; // ----------------------------------------------------- //>> Методы расширения типа integer # Extension methods for integer // ----------------------------------------------------- /// Возвращает True если целое делится на указанное значение function Divs(Self,d: integer): boolean; extensionmethod := Self mod d = 0; /// Возвращает True если целое не делится на указанное значение function NotDivs(Self,d: integer): boolean; extensionmethod := Self mod d <> 0; /// Возвращает True если целое делится на одно из значений function DivsAny(Self: integer; params a: array of integer): boolean; extensionmethod; begin Result := False; for var i:=0 to a.Length-1 do if Self mod a[i] = 0 then begin Result := True; exit end; end; /// Возвращает True если целое делится на все значения function DivsAll(Self: integer; params a: array of integer): boolean; extensionmethod; begin Result := True; for var i:=0 to a.Length-1 do if Self mod a[i] <> 0 then begin Result := False; exit end; end; /// Возвращает квадратный корень числа function Sqrt(Self: integer): real; extensionmethod; begin Result := Sqrt(Self); end; /// Возвращает квадрат числа function Sqr(Self: integer): int64; extensionmethod; begin Result := Sqr(Self); end; /// Возвращает True если значение находится между двумя другими function Between(Self: integer; a, b: integer): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b) or (b <= Self) and (Self <= a); end; /// Возвращает True если значение находится в диапазоне [a,b] function InRange(Self: integer; a,b: integer): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b); end; ///-- function InRangeInternal(x: integer; a,b: integer): boolean; begin Result := (a <= x) and (x <= b) end; ///-- function InRangeInternal(x: real; a,b: real): boolean; begin Result := (a <= x) and (x <= b) end; ///-- function InRangeInternal(x: char; a,b: char): boolean; begin Result := (a <= x) and (x <= b) end; // Дополнения февраль 2016: IsEven, IsOdd /// Возвращает, является ли целое четным function IsEven(Self: integer): boolean; extensionmethod; begin Result := Self mod 2 = 0; end; /// Возвращает, является ли целое нечетным function IsOdd(Self: integer): boolean; extensionmethod; begin Result := Self mod 2 <> 0; end; /// Возвращает последовательность чисел от 1 до данного function Range(Self: integer): sequence of integer; extensionmethod; begin Result := Range(1, Self); end; // Дополнения февраль 2016: &To, &Downto, Times /// Генерирует последовательность целых от текущего значения до n function &To(Self: integer; n: integer): sequence of integer; extensionmethod; begin Result := Range(Self, n); end; /// Генерирует последовательность целых от текущего значения до n в убывающем порядке function &Downto(Self: integer; n: integer): sequence of integer; extensionmethod; begin Result := Range(Self, n, -1); end; /// Возвращает последовательность целых 0,1,...n-1 function Times(Self: integer): sequence of integer; extensionmethod; begin Result := Range(0, Self - 1); end; /// Возвращает число, ограниченное диапазоном от bottom до top включительно function Clamp(Self: integer; bottom,top: integer): integer; extensionmethod; begin if bottom > top then raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); if Self < bottom then Result := bottom else if Self > top then Result := top else Result := Self; end; /// Возвращает число, ограниченное величиной top сверху function ClampTop(Self: integer; top: integer): integer; extensionmethod := Min(Self, top); /// Возвращает число, ограниченное величиной bottom снизу function ClampBottom(Self: integer; bottom: integer): integer; extensionmethod := Max(Self, bottom); // ----------------------------------------------------- //>> Методы расширения типа BigInteger # Extension methods for BigInteger // ----------------------------------------------------- /// Возвращает квадратный корень числа function Sqrt(Self: BigInteger): real; extensionmethod; begin Result := Sqrt(real(Self)); end; // ----------------------------------------------------- //>> Методы расширения типа real # Extension methods for real // ----------------------------------------------------- /// Возвращает True если значение находится в диапазоне [a,b] function Between(Self: real; a, b: real): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b) or (b <= Self) and (Self <= a); end; /// Возвращает True если значение находится в диапазоне [a, b] function InRange(Self: real; a,b: real): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b); end; /// Возвращает квадратный корень числа function Sqrt(Self: real): real; extensionmethod; begin Result := Sqrt(Self); end; /// Возвращает квадрат числа function Sqr(Self: real): real; extensionmethod; begin Result := Sqr(Self); end; /// Возвращает число, округленное до ближайшего целого function Round(Self: real): integer; extensionmethod; begin Result := Round(Self); end; /// Возвращает x, округленное до ближайшего вещественного с digits знаками после десятичной точки function Round(Self: real; digits: integer): real; extensionmethod; begin Result := Round(Self,digits); end; /// Возвращает число, округленное до ближайшего длинного целого function RoundBigInteger(Self: real): BigInteger; extensionmethod; begin Result := RoundBigInteger(Self); end; /// Возвращает целую часть вещественного числа function Trunc(Self: real): integer; extensionmethod; begin Result := Trunc(Self); end; /// Возвращает целую часть вещественного числа как длинное целое function TruncBigInteger(Self: real): BigInteger; extensionmethod; begin Result := TruncBigInteger(Self); end; /// Возвращает наибольшее целое, меньшее или равное вещественному числу function Floor(Self: real): integer; extensionmethod; begin Result := Floor(Self); end; /// Возвращает наменьшее целое, большее или равное вещественному числу function Ceil(Self: real): integer; extensionmethod; begin Result := Ceil(Self); end; /// Возвращает вещественное, отформатированное к строке с frac цифрами после десятичной точки function ToString(Self: real; frac: integer): string; extensionmethod; begin if frac < 0 then raise new System.ArgumentOutOfRangeException('frac', 'frac<0'); if frac >= 100 then raise new System.ArgumentOutOfRangeException('frac', 'frac>=100'); Result := Format('{0:f' + frac + '}', Self) end; /// Возвращает число, ограниченное диапазоном от bottom до top включительно function Clamp(Self: real; bottom,top: real): real; extensionmethod; begin if bottom > top then raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); if Self < bottom then Result := bottom else if Self > top then Result := top else Result := Self; end; /// Возвращает число, ограниченное величиной top сверху function ClampTop(Self: real; top: real): real; extensionmethod := Min(Self, top); /// Возвращает число, ограниченное величиной bottom снизу function ClampBottom(Self: real; bottom: real): real; extensionmethod := Max(Self, bottom); //------------------------------------------------------------------------------ //>> Методы расширения типа char # Extension methods for char //------------------------------------------------------------------------------ /// Возвращает True если значение находится между двумя другими function Between(Self: char; a, b: char): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b) or (b <= Self) and (Self <= a); end; /// Возвращает True если символ находится в диапазоне [a,b] function InRange(Self: char; a,b: char): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b); end; /// Предыдущий символ function Pred(Self: char); extensionmethod := PABCSystem.Pred(Self); /// Следующий символ function Succ(Self: char); extensionmethod := PABCSystem.Succ(Self); /// Код символа в кодировке Unicode function Code(Self: char): integer; extensionmethod := word(Self); /// Является ли символ цифрой function IsDigit(Self: char); extensionmethod := char.IsDigit(Self); /// Является ли символ буквой function IsLetter(Self: char): boolean; extensionmethod; begin Result := char.IsLetter(Self); end; /// Принадлежит ли символ к категории букв нижнего регистра function IsLower(Self: char): boolean; extensionmethod; begin Result := char.IsLower(Self); end; /// Принадлежит ли символ к категории букв верхнего регистра function IsUpper(Self: char): boolean; extensionmethod; begin Result := char.IsUpper(Self); end; /// Преобразует символ в цифру function ToDigit(Self: char): integer; extensionmethod; begin Result := OrdUnicode(Self) - OrdUnicode('0'); if (Result < 0) or (Result >= 10) then raise new System.FormatException('not a Digit'); end; /// Преобразует символ в нижний регистр function ToLower(Self: char): char; extensionmethod; begin Result := char.ToLower(Self); end; /// Преобразует символ в верхний регистр function ToUpper(Self: char): char; extensionmethod; begin Result := char.ToUpper(Self); end; //------------------------------------------------------------------------------ //>> Методы расширения типа string # Extension methods for string //------------------------------------------------------------------------------ /// Заменяет count вхождений подстроки oldStr на подстроку newStr в исходной строке function Replace(Self: string; oldStr,newStr: string; count: integer): string; extensionmethod; begin //var reg := new Regex(Regex.Escape(oldStr)); //Result := reg.Replace(Self,newStr,count); Result := Self.Split(|oldStr|, count+1, System.StringSplitOptions.None).JoinToString(newStr); end; /// Возвращает True если строка находится между двумя другими (лексикографическое сравнение) function Between(Self: string; a, b: string): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b) or (b <= Self) and (Self <= a); end; /// Возвращает True если строка находится в диапазоне [a,b] (лексикографическое сравнение) function InRange(Self: string; a, b: string): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b); end; /// Считывает целое из строки начиная с позиции from и устанавливает from за считанным значением function ReadInteger(Self: string; var from: integer): integer; extensionmethod; begin var from1 := from + 1; Result := ReadIntegerFromString(Self, from1); from := from1 - 1; end; /// Считывает вещественное из строки начиная с позиции from и устанавливает from за считанным значением function ReadReal(Self: string; var from: integer): real; extensionmethod; begin var from1 := from + 1; Result := ReadRealFromString(Self, from1); from := from1 - 1; end; /// Считывает слово из строки начиная с позиции from и устанавливает from за считанным значением function ReadWord(Self: string; var from: integer): string; extensionmethod; begin var from1 := from + 1; Result := ReadwordFromString(Self, from1); from := from1 - 1; end; /// Преобразует строку в целое function ToInteger(Self: string): integer; extensionmethod := StrToInt(Self); /// Преобразует строку в BigInteger function ToBigInteger(Self: string): BigInteger; extensionmethod := BigInteger.Parse(Self); /// Преобразует строку в вещественное function ToReal(Self: string): real; extensionmethod := real.Parse(Self, nfi); /// Преобразует строку в вещественное function ToReal(Self: string; nfi: NumberFormatInfo): real; extensionmethod := real.Parse(Self, nfi); /// Преобразует строку в вещественное function ToReal(Self: string; DecimalSeparator: string): real; extensionmethod := Self.ToReal(NumberFormat(DecimalSeparator)); /// Преобразует строку в целое и записывает его в value. ///При невозможности преобразования возвращается False function TryToInteger(Self: string; var value: integer): boolean; extensionmethod := TryStrToInt(Self,value); /// Преобразует строку в вещественное и записывает его в value. ///При невозможности преобразования возвращается False function TryToReal(Self: string; var value: real): boolean; extensionmethod := TryStrToReal(Self,value); /// Возвращает True если строку можно преобразовать в вещественное function IsReal(Self: string): boolean; extensionmethod; begin var r: real; Result := TryStrToReal(Self, r); end; /// Возвращает True если строку можно преобразовать в целое function IsInteger(Self: string): boolean; extensionmethod; begin var i: integer; Result := TryStrToInt(Self, i); end; /// Преобразует строку в целое ///При невозможности преобразования возвращается defaultvalue function ToInteger(Self: string; defaultvalue: integer): integer; extensionmethod; begin var b := TryStrToInt(Self,Result); if not b then Result := defaultvalue end; /// Преобразует строку в вещественное ///При невозможности преобразования возвращается defaultvalue function ToReal(Self: string; defaultvalue: real): real; extensionmethod; begin var b := TryStrToReal(Self,Result); if not b then Result := defaultvalue end; /// Преобразует строку в массив слов function ToWords(Self: string; params delim: array of char): array of string; extensionmethod; begin Result := Self.Split(delim, System.StringSplitOptions.RemoveEmptyEntries); end; /// Преобразует строку в массив слов, используя в качестве разделителей символы из строки delims function ToWords(Self: string; delims: string := ' '): array of string; extensionmethod; begin Result := Self.Split(delims.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries); end; /// Преобразует многострочную строку в массив строк function ToLines(Self: string): array of string; extensionmethod; begin Result := Self.Split(| #13#10, // CR+LF: Win #10, // LF: Linux #13 // CR: Mac // https://en.m.wikipedia.org/wiki/Newline#Unicode // But standard .Net things like System.IO.StringReader don't support these, so for now - commented out // #11, // Vertical Tab // #12, // Form feed // char($85), // Next Line // char($2028), // Line Separator // char($2029), // Paragraph SeparatorS |, System.StringSplitOptions.None); end; procedure PassSpaces(var s: string; var from: integer); begin while (from <= s.Length) and char.IsWhiteSpace(s[from]) do from += 1; end; /// Преобразует строку в массив целых function ToIntegers(Self: string): array of integer; extensionmethod; begin //Result := Self.ToWords().ConvertAll(s -> StrToInt(s)); // SSM ускорение в 5 раз 19.01.20 var l := new List(10); var from := 1; while from <= Self.Length do begin l.Add(ReadIntegerFromString(Self,from)); PassSpaces(Self,from); end; Result := l.ToArray; end; /// Считывает из строки массив из N целых function ToIntegers(Self: string; N: integer): array of integer; extensionmethod; begin // SSM Скорость работы на 30% выше чем у ToIntegers без параметров Result := new integer[N]; var from := 0; for var i:=0 to N-1 do Result[i] := Self.ReadInteger(from); end; /// Преобразует строку в массив вещественных function ToReals(Self: string): array of real; extensionmethod; begin Result := Self.ToWords(' '#9#10#13).ConvertAll(s -> StrToFloat(s)); end; /// Преобразует строку в массив вещественных function ToReals(Self: string; nfi: NumberFormatInfo): array of real; extensionmethod; begin Result := Self.ToWords(' '#9#10#13).ConvertAll(s -> StrToFloat(s,nfi)); end; /// Преобразует строку в массив вещественных function ToReals(Self: string; DecimalSeparator: string): array of real; extensionmethod; begin var nfi := NumberFormat(DecimalSeparator); Result := Self.ToWords(' '#9#10#13).ConvertAll(s -> StrToFloat(s,nfi)); end; /// Возвращает инверсию строки function Inverse(Self: string): string; extensionmethod; begin var sb := new System.Text.StringBuilder(Self.Length); for var i := Self.Length downto 1 do sb.Append(Self[i]); Result := sb.ToString; end; // Дополнения февраль 2016: Matches, MatchValue, MatchValues, IsMatch, RegexReplace, Remove, Right, Left /// Заменяет в указанной строке все вхождения регулярного выражения указанной строкой замены и возвращает преобразованную строку function RegexReplace(Self: string; reg, repl: string; options: RegexOptions := RegexOptions.None): string; extensionmethod; begin Result := Regex.Replace(Self, reg, repl, options) end; /// Заменяет в указанной строке все вхождения регулярного выражения указанным преобразованием замены и возвращает преобразованную строку function RegexReplace(Self: string; reg: string; repl: &Match->string; options: RegexOptions := RegexOptions.None): string; extensionmethod; begin Result := Regex.Replace(Self, reg, repl, options) end; /// Ищет в указанной строке все вхождения регулярного выражения и возвращает их в виде последовательности элементов типа Match function Matches(Self: string; reg: string; options: RegexOptions := RegexOptions.None): sequence of &Match; extensionmethod; begin Result := (new Regex(reg, options)).Matches(Self).Cast&<&Match>(); end; /// Ищет в указанной строке первое вхождение регулярного выражения и возвращает его в виде строки function MatchValue(Self: string; reg: string; options: RegexOptions := RegexOptions.None): string; extensionmethod; begin Result := (new Regex(reg, options)).&Match(Self).Value; end; /// Ищет в указанной строке все вхождения регулярного выражения и возвращает их в виде последовательности строк function MatchValues(Self: string; reg: string; options: RegexOptions := RegexOptions.None): sequence of string; extensionmethod; begin Result := Self.Matches(reg, options).Select(m -> m.Value); end; /// Удовлетворяет ли строка регулярному выражению function IsMatch(Self: string; reg: string; options: RegexOptions := RegexOptions.None): boolean; extensionmethod := Regex.IsMatch(Self, reg, options); /// Удаляет в строке все вхождения указанных строк function Remove(Self: string; params targets: array of string): string; extensionmethod; begin var builder := new StringBuilder(Self); for var i := 0 to targets.Length - 1 do builder.Replace(targets[i], String.Empty); Result := builder.ToString(); end; /// Возвращает подстроку, полученную вырезанием из строки length самых правых символов function Right(Self: string; length: integer): string; extensionmethod; begin length := Max(length, 0); if Self.Length > length then Result := Self.Substring(Self.Length - length, length) else Result := Self; end; /// Возвращает подстроку, полученную вырезанием из строки length самых левых символов function Left(Self: string; length: integer): string; extensionmethod; begin length := Max(length, 0); if Self.Length > length then Result := Self.Substring(0, length) else Result := Self; end; function PrefixFunction(s: string): array of integer; // возвращает массив граней для строки-аргумента begin var n := s.Length; Result := ArrFill(n + 1, 0); for var i := 1 to n - 1 do begin var temp := Result[i]; while (temp > 0) and (s[i + 1] <> s[temp + 1]) do temp := Result[temp]; Result[i + 1] := s[i + 1] = s[temp + 1] ? temp + 1 : 0 end end; /// Возвращает последовательность индексов вхождений подстроки в основную строку ///Параметр overlay определяет, разрешены ли перекрытия вхождений подстрок function IndicesOf(Self, SubS: string; overlay: boolean := False): sequence of integer; extensionmethod; // Реализует КМП-алгоритм. begin var L := new List; var (n, m) := (Self.Length, SubS.Length); var border := PrefixFunction(SubS); var temp := 0; for var i := 1 to n do begin while (temp > 0) and (SubS[temp + 1] <> Self[i]) do temp := border[temp]; if SubS[temp + 1] = Self[i] then temp += 1; if temp = m then begin var pos := i - m + 1; if overlay or (L.Count = 0) or (pos >= L[L.Count - 1] + m) then L.Add(pos); temp := border[m] end; end; Result := L.Select(i -> i - 1) end; /// Возвращает случайный символ строки function RandomElement(Self: string): char; extensionmethod; begin Result := Self[Random(Self.Length)+1]; end; ///-- function CreateSliceFromStringInternal(Self: string; from, step, count: integer): string; begin var res := new StringBuilder(count); loop count do begin res.Append(Self[from]); from += step; end; Result := res.ToString; end; ///-- function SliceStringImpl(Self: string; from, step, count: integer): string; begin {if step = 0 then raise new ArgumentException(GetTranslation(PARAMETER_STEP_MUST_BE_NOT_EQUAL_0)); if (from < 0) or (from > Self.Length - 1) then raise new ArgumentException(GetTranslation(PARAMETER_FROM_OUT_OF_RANGE)); var cnt := step > 0 ? Self.Length - from : from + 1; var cntstep := (cnt-1) div abs(step) + 1; if count > cntstep then count := cntstep;} CorrectCountForSlice(Self.Length, from, step, count); Result := CreateSliceFromStringInternal(Self, from + 1, step, count); end; /// Возвращает срез строки от индекса from с шагом step function Slice(Self: string; from, step: integer): string; extensionmethod; begin Result := SliceStringImpl(Self, from, step, integer.MaxValue); end; /// Возвращает срез строки от индекса from с шагом step длины не более count function Slice(Self: string; from, step, count: integer): string; extensionmethod; begin Result := SliceStringImpl(Self, from, step, count); end; ///-- function SystemSliceStringImpl(Self: string; situation: integer; from, &to: integer; step: integer := 1; baseIndex: integer := 1): string; begin var fromv := from - baseIndex; var tov := &to - baseIndex; var count := CheckAndCorrectFromToAndCalcCountForSystemSlice(situation, Self.Length, fromv, tov, step); if step = 1 then // Opt s[a:b] Result := Self.Substring(fromv,count) else Result := CreateSliceFromStringInternal(Self, fromv + 1, step, count) end; ///-- function SystemSlice(Self: string; situation: integer; from, &to: integer; step: integer := 1): string; extensionmethod; begin Result := SystemSliceStringImpl(Self, situation, from, &to, step); end; ///-- function SystemSlice0(Self: string; situation: integer; from, &to: integer; step: integer := 1): string; extensionmethod; begin Result := SystemSliceStringImpl(Self, situation, from, &to, step, 0); // 0 - ZeroBased end; ///-- function SystemSlice(Self: string; situation: integer; from, &to: SystemIndex; step: integer := 1): string; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue + 1; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue + 1; Result := SystemSliceStringImpl(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSlice0(Self: string; situation: integer; from, &to: SystemIndex; step: integer := 1): string; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue; Result := SystemSliceStringImpl(Self, situation, from.IndexValue, &to.IndexValue, step, 0); end; ///-- function SystemSliceStringImplQuestion(Self: string; situation: integer; from, &to: integer; step: integer := 1; baseIndex: integer := 1): string; begin var fromv := from - baseIndex; var tov := &to - baseIndex; var count := CorrectFromToAndCalcCountForSystemSliceQuestion(situation, Self.Length, fromv, tov, step); Result := CreateSliceFromStringInternal(Self, fromv + 1, step, count); end; ///-- function SystemSliceQuestion(Self: string; situation: integer; from, &to: SystemIndex; step: integer := 1): string; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue + 1; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue + 1; Result := SystemSliceStringImplQuestion(Self, situation, from.IndexValue, &to.IndexValue, step); end; ///-- function SystemSliceQuestion0(Self: string; situation: integer; from, &to: SystemIndex; step: integer := 1): string; extensionmethod; begin if from.IsInverted then from.IndexValue := Self.Count - from.IndexValue + 1; if &to.IsInverted then &to.IndexValue := Self.Count - &to.IndexValue + 1; Result := SystemSliceStringImplQuestion(Self, situation, from.IndexValue, &to.IndexValue, step, 0); end; //-------------------------------------------- //>> Методы расширения типа faststring (StringBuilder) # Extension methods for faststring (StringBuilder) //-------------------------------------------- /// Возвращает индекс вхождения подстроки в быструю строку function IndexOf(Self: faststring; subs: string; from: integer := 0): integer; extensionmethod; begin var lens := Self.Length; var lens1 := subs.Length; if (from < 0) or (lens1 > lens - from) then begin Result := -1; exit; end; if lens1 = 0 then begin Result := from; exit; end; for var i := from to lens - lens1 do begin var found := True; for var j := 0 to lens1 - 1 do begin if Self[i + j] <> subs[j + 1] then begin found := False; break; end; end; if found then begin Result := i; exit; end; end; Result := -1; end; /// Преобразует быструю строку в последовательность символов function ToSequence(Self: faststring): sequence of char; extensionmethod; begin for var i:=0 to Self.Length - 1 do yield Self[i]; end; function operator in(subs: string; s: faststring): boolean; extensionmethod; begin Result := s.IndexOf(subs) <> -1; end; /// Замещает n вхождений указанной строки на другую строку (все при n = 0) function Replace(Self: faststring; OldValue, NewValue: string; n: integer): faststring; extensionmethod; begin if n = 0 then Self.Replace(OldValue, NewValue) // стандартный метод StringBuilder else begin var from := 0; loop n do begin var index := Self.IndexOf(OldValue, from); if index = -1 then exit; Self.Remove(index, OldValue.Length); Self.Insert(index, NewValue); from := index + NewValue.Length; end; end; Result := Self; end; //-------------------------------------------- //>> Методы расширения типа Func # Extension methods for Func //-------------------------------------------- /// Суперпозиция функций function Compose(Self: T2->TResult; composer: T1->T2): T1->TResult; extensionmethod; begin if composer = nil then raise new System.ArgumentNullException('composer'); var Slf := Self; Result := x -> Slf(composer(x)); end; //------------------------------------------------------------------------------ //>> Методы расширения типа Complex # Extension methods for Complex //------------------------------------------------------------------------------ /// Возвращает комплексно сопряженное значение function Conjugate(Self: Complex): Complex; extensionmethod; begin Result := Complex.Conjugate(Self); end; // ----------------------------------------------------------------------------- //>> Методы расширения словарей # Extension methods for IDictionary // ----------------------------------------------------------------------------- /// Возвращает в словаре значение, связанное с указанным ключом, а если такого ключа нет, то значение по умолчанию function Get(Self: IDictionary; K: Key; V: Value := default(Value)): Value; extensionmethod; begin var b := Self.TryGetValue(K, Result); if not b then Result := V; end; /// Возвращает словарь, сопоставляющий ключу группы количество элементов с данным ключом function EachCount(Self: sequence of System.Linq.IGrouping): Dictionary; extensionmethod; begin Result := Self.ToDictionary(g -> g.Key, g -> g.Count); end; /// Возвращает частотный словарь объектов последовательности function EachCount(Self: sequence of T): Dictionary; extensionmethod; begin Result := Self.GroupBy(x->x).ToDictionary(g -> g.Key, g -> g.Count); end; /// Возвращает словарь, сопоставляющий ключу группы результат групповой операции function Each(Self: sequence of System.Linq.IGrouping; grOperation: System.Linq.IGrouping -> Res): Dictionary; extensionmethod; begin Result := Self.ToDictionary(g -> g.Key, g -> grOperation(g)); end; /// Возвращает словарь, сопоставляющий элементам последовательности определённые значения function Each(Self: sequence of Key; proj: Key -> Res): Dictionary; extensionmethod; begin Result := Self.GroupBy(x->x).ToDictionary(g -> g.Key, g -> proj(g.Key)); end; /// Обновляет данные в словаре данными из другого словаря procedure Update(Self: Dictionary; update: Dictionary); extensionmethod; begin foreach var kv in update do Self[kv.Key] := kv.Value; end; /// Обновляет данные в словаре данными из другого словаря procedure operator+=(Self: Dictionary; update: Dictionary); extensionmethod; begin foreach var kv in update do Self[kv.Key] := kv.Value; end; /// Объединяет данные в двух словарях. Если в обоих имеются одинаковые ключи, то с ключом связывается значение из второго словаря function operator+(Self: Dictionary; dict: Dictionary): Dictionary; extensionmethod; begin var d := PABCSystem.Dict(Self); d += dict; Result := d; end; /// Удаляет из словаря пары с указанным значением ключа procedure operator-=(Self: IDictionary; k: Key); extensionmethod; begin Self.Remove(k); end; /// Удаляет из словаря пары с указанными значениями ключа procedure operator-=(Self: IDictionary; keys: sequence of Key); extensionmethod; begin foreach var k in keys do Self.Remove(k); end; /// Возвращает словарь, в котором из исходного словаря удален элемент с данным ключом function operator-(Self: Dictionary; key: TKey): Dictionary; extensionmethod; begin var d := Dict(Self); d -= key; Result := d; end; /// Возвращает словарь, в котором из исходного словаря удалены все элементы с ключами, задаваемыми вторым операндом function operator-(Self: Dictionary; keys: sequence of TKey): Dictionary; extensionmethod; begin var d := Dict(Self); d -= keys; Result := d; end; // -------------------------------------------- //>> Методы расширения типа Tuple # Extension methods for Tuple // ------------------------------------------- // Дополнения февраль 2016 /// Добавляет поле к кортежу function Add(Self: (T1, T2); v: T3): (T1, T2, T3); extensionmethod; begin Result := (Self[0], Self[1], v); end; /// Добавляет поле к кортежу function Add(Self: (T1, T2, T3); v: T4): (T1, T2, T3, T4); extensionmethod; begin Result := (Self[0], Self[1], Self[2], v); end; /// Добавляет поле к кортежу function Add(Self: (T1, T2, T3, T4); v: T5): (T1, T2, T3, T4, T5); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], v); end; /// Добавляет поле к кортежу function Add(Self: (T1, T2, T3, T4, T5); v: T6): (T1, T2, T3, T4, T5, T6); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], Self[4], v); end; /// Добавляет поле к кортежу function Add(Self: (T1, T2, T3, T4, T5, T6); v: T7): (T1, T2, T3, T4, T5, T6, T7); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], Self[4], Self[5], v); end; /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2)); extensionmethod := Print(Self); /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2, T3)); extensionmethod := Print(Self); /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2, T3, T4)); extensionmethod := Print(Self); /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2, T3, T4, T5)); extensionmethod := Print(Self); /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2, T3, T4, T5, T6)); extensionmethod := Print(Self); /// Выводит кортеж на экран, после чего выводит пробел procedure Print(Self: (T1, T2, T3, T4, T5, T6, T7)); extensionmethod := Print(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2)); extensionmethod := Println(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2, T3)); extensionmethod := Println(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2, T3, T4)); extensionmethod := Println(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2, T3, T4, T5)); extensionmethod := Println(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2, T3, T4, T5, T6)); extensionmethod := Println(Self); /// Выводит кортеж на экран и переходит на новую строку procedure Println(Self: (T1, T2, T3, T4, T5, T6, T7)); extensionmethod := Println(Self); /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T)): array of T; extensionmethod := |Self[0],Self[1]|; /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T,T)): array of T; extensionmethod := |Self[0],Self[1],Self[2]|; /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T,T,T)): array of T; extensionmethod := |Self[0],Self[1],Self[2],Self[3]|; /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T,T,T,T)): array of T; extensionmethod := |Self[0],Self[1],Self[2],Self[3],Self[4]|; /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T,T,T,T,T)): array of T; extensionmethod := |Self[0],Self[1],Self[2],Self[3],Self[4],Self[5]|; /// Преобразует кортеж элементов одного типа в массив function ToArray(Self: (T,T,T,T,T,T,T)): array of T; extensionmethod := |Self[0],Self[1],Self[2],Self[3],Self[4],Self[5],Self[6]|; //{{{--doc: Конец методов расширения }}} //------------------------------------------------------------------------------ // Операции для Func //------------------------------------------------------------------------------ ///-- function operator*(Self: T2->TResult; composer: T1->T2): T1->TResult; extensionmethod; begin if composer = nil then raise new System.ArgumentNullException('composer'); Result := Self.Compose(composer); end; //------------------------------------------------------------------------------ // Операции для Tuple //------------------------------------------------------------------------------ ///-- function operator+(Self: (T1, T2); v: T3): (T1, T2, T3); extensionmethod; begin Result := (Self[0], Self[1], v); end; ///-- function operator+(Self: (T1, T2, T3); v: T4): (T1, T2, T3, T4); extensionmethod; begin Result := (Self[0], Self[1], Self[2], v); end; ///-- function operator+(Self: (T1, T2, T3, T4); v: T5): (T1, T2, T3, T4, T5); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], v); end; ///-- function operator+(Self: (T1, T2, T3, T4, T5); v: T6): (T1, T2, T3, T4, T5, T6); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], Self[4], v); end; ///-- function operator+(Self: (T1, T2, T3, T4, T5, T6); v: T7): (T1, T2, T3, T4, T5, T6, T7); extensionmethod; begin Result := (Self[0], Self[1], Self[2], Self[3], Self[4], Self[5], v); end; ///-- function InternalEqual (x: (T1,T2); y: (T1,T2)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2); y: (T1,T2)): boolean; extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2); y: (T1,T2)): boolean; extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup2(v1: (T1, T2); v2: (T1, T2)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2); v: (T1, T2)); extensionmethod := CompareToTup2(Self, v) < 0; ///-- function operator<=(Self: (T1, T2); v: (T1, T2)); extensionmethod := CompareToTup2(Self, v) <= 0; ///-- function operator>(Self: (T1, T2); v: (T1, T2)); extensionmethod := CompareToTup2(Self, v) > 0; ///-- function operator>=(Self: (T1, T2); v: (T1, T2)); extensionmethod := CompareToTup2(Self, v) >= 0; ///-- function InternalEqual (x: (T1,T2,T3); y: (T1,T2,T3)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2,T3); y: (T1,T2,T3)); extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2,T3); y: (T1,T2,T3)); extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup3(v1: (T1, T2, T3); v2: (T1, T2, T3)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2, T3); v: (T1, T2, T3)); extensionmethod := CompareToTup3(Self, v) < 0; ///-- function operator<=(Self: (T1, T2, T3); v: (T1, T2, T3)); extensionmethod := CompareToTup3(Self, v) <= 0; ///-- function operator>(Self: (T1, T2, T3); v: (T1, T2, T3)); extensionmethod := CompareToTup3(Self, v) > 0; ///-- function operator>=(Self: (T1, T2, T3); v: (T1, T2, T3)); extensionmethod := CompareToTup3(Self, v) >= 0; ///-- function InternalEqual (x: (T1,T2,T3,T4); y: (T1,T2,T3,T4)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2,T3,T4); y: (T1,T2,T3,T4)); extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2,T3,T4); y: (T1,T2,T3,T4)); extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup4(v1: (T1, T2, T3, T4); v2: (T1, T2, T3, T4)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2, T3, T4); v: (T1, T2, T3, T4)); extensionmethod := CompareToTup4(Self, v) < 0; ///-- function operator<=(Self: (T1, T2, T3, T4); v: (T1, T2, T3, T4)); extensionmethod := CompareToTup4(Self, v) <= 0; ///-- function operator>(Self: (T1, T2, T3, T4); v: (T1, T2, T3, T4)); extensionmethod := CompareToTup4(Self, v) > 0; ///-- function operator>=(Self: (T1, T2, T3, T4); v: (T1, T2, T3, T4)); extensionmethod := CompareToTup4(Self, v) >= 0; ///-- function InternalEqual (x: (T1,T2,T3,T4,T5); y: (T1,T2,T3,T4,T5)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2,T3,T4,T5); y: (T1,T2,T3,T4,T5)); extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2,T3,T4,T5); y: (T1,T2,T3,T4,T5)); extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup5(v1: (T1, T2, T3, T4,T5); v2: (T1, T2, T3, T4,T5)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2, T3, T4,T5); v: (T1, T2, T3, T4,T5)); extensionmethod := CompareToTup5(Self, v) < 0; ///-- function operator<=(Self: (T1, T2, T3, T4,T5); v: (T1, T2, T3, T4,T5)); extensionmethod := CompareToTup5(Self, v) <= 0; ///-- function operator>(Self: (T1, T2, T3, T4,T5); v: (T1, T2, T3, T4,T5)); extensionmethod := CompareToTup5(Self, v) > 0; ///-- function operator>=(Self: (T1, T2, T3, T4,T5); v: (T1, T2, T3, T4,T5)); extensionmethod := CompareToTup5(Self, v) >= 0; ///-- function InternalEqual (x: (T1,T2,T3,T4,T5,T6); y: (T1,T2,T3,T4,T5,T6)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2,T3,T4,T5,T6); y: (T1,T2,T3,T4,T5,T6)); extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2,T3,T4,T5,T6); y: (T1,T2,T3,T4,T5,T6)); extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup5(v1: (T1, T2, T3, T4,T5,T6); v2: (T1, T2, T3, T4,T5,T6)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2, T3, T4,T5,T6); v: (T1, T2, T3, T4,T5,T6)); extensionmethod := CompareToTup5(Self, v) < 0; ///-- function operator<=(Self: (T1, T2, T3, T4,T5,T6); v: (T1, T2, T3, T4,T5,T6)); extensionmethod := CompareToTup5(Self, v) <= 0; ///-- function operator>(Self: (T1, T2, T3, T4,T5,T6); v: (T1, T2, T3, T4,T5,T6)); extensionmethod := CompareToTup5(Self, v) > 0; ///-- function operator>=(Self: (T1, T2, T3, T4,T5,T6); v: (T1, T2, T3, T4,T5,T6)); extensionmethod := CompareToTup5(Self, v) >= 0; ///-- function InternalEqual (x: (T1,T2,T3,T4,T5,T6,T7); y: (T1,T2,T3,T4,T5,T6,T7)): boolean; begin var xn := Object.ReferenceEquals(x,nil); var yn := Object.ReferenceEquals(y,nil); if xn then Result := yn else if yn then Result := xn else Result := x.Equals(y); end; ///-- function operator= (x: (T1,T2,T3,T4,T5,T6,T7); y: (T1,T2,T3,T4,T5,T6,T7)); extensionmethod := InternalEqual(x,y); ///-- function operator<> (x: (T1,T2,T3,T4,T5,T6,T7); y: (T1,T2,T3,T4,T5,T6,T7)); extensionmethod := not InternalEqual(x,y); ///-- function CompareToTup5(v1: (T1, T2, T3, T4,T5,T6,T7); v2: (T1, T2, T3, T4,T5,T6,T7)) := (v1 as System.IComparable).CompareTo(v2); ///-- function operator<(Self: (T1, T2, T3, T4,T5,T6,T7); v: (T1, T2, T3, T4,T5,T6,T7)); extensionmethod := CompareToTup5(Self, v) < 0; ///-- function operator<=(Self: (T1, T2, T3, T4,T5,T6,T7); v: (T1, T2, T3, T4,T5,T6,T7)); extensionmethod := CompareToTup5(Self, v) <= 0; ///-- function operator>(Self: (T1, T2, T3, T4,T5,T6,T7); v: (T1, T2, T3, T4,T5,T6,T7)); extensionmethod := CompareToTup5(Self, v) > 0; ///-- function operator>=(Self: (T1, T2, T3, T4,T5,T6,T7); v: (T1, T2, T3, T4,T5,T6,T7)); extensionmethod := CompareToTup5(Self, v) >= 0; {// Определяет, есть ли указанный элемент в массиве function Contains(self: array of T; x: T): boolean; extensionmethod; begin Result := System.Array.IndexOf(self,x)<>-1; end;} {// Изменяет порядок элементов в массиве на обратный procedure Reverse(self: array of T); extensionmethod; begin System.Array.Reverse(self); end; // Изменяет порядок элементов на обратный в диапазоне массива, заданном началом и длиной procedure Reverse(self: array of T; index,len: integer); extensionmethod; begin System.Array.Reverse(self,index,len); end;} //{{{ Конец секции реализации прикладных методов }}} //{{{ Начало секции реализации внутренних системных методов }}} // ----------------------------------------------------- // Standard Exceptions: implementation // ----------------------------------------------------- constructor BadGenericInstanceParameterException.Create(ActualParameterType: System.Type); begin InstanceType := ActualParameterType; end; function CanNotUseTypeForPointersException.ToString: string; begin result := InstanceType.FullName + ' непригоден для указателей.'; end; function CanNotUseTypeForTypedFilesException.ToString: string; begin result := InstanceType.FullName + ' непригоден для типизированных файлов.'; end; function CanNotUseTypeForFilesException.ToString: string; begin result := InstanceType.FullName + ' непригоден для файлов.'; end; // ----------------------------------------------------- // Internal System subprograms: implementation // ----------------------------------------------------- function check_in_range(val: int64; low, up: int64): int64; begin if (val < low) or (val > up) then raise new RangeException(GetTranslation(RANGE_ERROR_MESSAGE)); Result := val; end; function check_in_range_char(val: char; low, up: char): char; begin if (val < low) or (val > up) then raise new RangeException(GetTranslation(RANGE_ERROR_MESSAGE)); Result := val; end; function RunTimeSizeOf(t: System.Type): integer; var t1: System.Type; elem: object; fa: array of System.Reflection.FieldInfo; NullBasedArray: System.Array; fi: System.Reflection.FieldInfo; begin if t.IsPrimitive or t.IsEnum then //begin case System.Type.GetTypeCode(t) of TypeCode.Boolean: Result := sizeof(Boolean); TypeCode.Byte: Result := sizeof(Byte); TypeCode.Char: Result := 1;//sizeof(Char); TypeCode.Decimal: Result := sizeof(Decimal); TypeCode.Double: Result := sizeof(Double); TypeCode.Int16: Result := sizeof(Int16); TypeCode.Int32: Result := sizeof(Int32); TypeCode.Int64: Result := sizeof(Int64); TypeCode.UInt16: Result := sizeof(UInt16); TypeCode.UInt32: Result := sizeof(UInt32); TypeCode.UInt64: Result := sizeof(UInt64); TypeCode.SByte: Result := sizeof(SByte); TypeCode.Single: Result := sizeof(Single); else if t.IsEnum then Result := sizeof(integer); end//; //end else if t.IsValueType then // it is a record begin //elem := Activator.CreateInstance(t); //ssyy commented fa := t.GetFields(System.Reflection.BindingFlags.GetField or System.Reflection.BindingFlags.Instance or System.Reflection.BindingFlags.Public or System.Reflection.BindingFlags.NonPublic); Result := 0; for var i := 0 to fa.Length - 1 do if {not fa[i].IsStatic and} not fa[i].IsLiteral then Result := Result + RunTimeSizeOf(fa[i].FieldType) end else if t = typeof(string) then Result := 0 else if t = typeof(TypedSet) then begin //elem := Activator.CreateInstance(t); //ssyy commented Result := 256 div 8; end else begin fi := t.GetField(InternalNullBasedArrayName); if fi = nil then raise new SystemException(GetTranslation(BAD_TYPE_IN_RUNTIMESIZEOF)); elem := Activator.CreateInstance(t); NullBasedArray := GetNullBasedArray(elem); t1 := NullBasedArray.GetType.GetElementType; Result := RunTimeSizeOf(t1) * NullBasedArray.Length; end; end; // ----------------------------------------------------------------------------- // Внутренние функции для работы с короткими строками // ----------------------------------------------------------------------------- [System.Diagnostics.DebuggerStepThrough] function GetCharInShortString(s: string; ind, n: integer): char; begin if ind < 0 then raise new IndexOutOfRangeException; if ind = 0 then Result := char(s.Length) else try Result := s[ind]; except on e: Exception do if ind > n then raise; end; end; [System.Diagnostics.DebuggerStepThrough] function SetCharInShortString(s: string; ind, n: integer; c: char): string; begin if ind < 0 then raise new IndexOutOfRangeException; if ind <> 0 then begin var sb := new System.Text.StringBuilder(); sb.Append(s); if ind - 1 < sb.Length then sb[ind - 1] := c; if ind > n then raise new IndexOutOfRangeException; Result := sb.ToString; end else begin //Result := s.PadRight(integer(c)); raise new IndexOutOfRangeException; end; end; [System.Diagnostics.DebuggerStepThrough] function ClipShortString(s: string; len: integer): string; begin if s = nil then Result := '' else if s.Length <= len then Result := s else Result := s.Substring(0, len); end; function GetResourceStream(ResourceFileName: string): Stream; begin Result := System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream(ResourceFileName); end; function FormatValue(value: object; NumOfChars: integer): string; begin if value <> nil then Result := ObjectToString(value) else Result := 'nil'; Result := Result.PadLeft(NumOfChars); end; function FormatValue(value: integer; NumOfChars: integer): string; begin Result := value.ToString; Result := Result.PadLeft(NumOfChars); end; function FormatValue(value: int64; NumOfChars: integer): string; begin Result := value.ToString; Result := Result.PadLeft(NumOfChars); end; function FormatValue(value: real; NumOfChars: integer): string; begin Result := value.ToString(nfi); Result := Result.PadLeft(NumOfChars); end; function FormatValue(value: real; NumOfChars, NumOfSignesAfterDot: integer): string; begin // SSM 31.03.09 var FmtStr := '{0,' + NumOfChars.ToString + ':f' + abs(NumOfSignesAfterDot).ToString + '}'; Result := Format(FmtStr, value); end; procedure StringDefaultPropertySet(var s: string; index: integer; c: char); begin var chars := s.ToCharArray; chars[index] := c; s := new String(chars); end; procedure ChangeChar(var c: char; val: char); begin c := val; end; procedure CheckCanUsePointerOnType(T: System.Type); begin if T.IsPointer then begin CheckCanUsePointerOnType(T.GetElementType()); exit; end; if T.IsValueType then begin var fields := T.GetFields(); foreach var fi in fields do if not fi.IsStatic then CheckCanUsePointerOnType(fi.FieldType); exit; end; raise new CanNotUseTypeForPointersException(T); end; procedure CheckCanUseTypeForFiles(T: System.Type; FileIsBinary: boolean); var fields: array of System.Reflection.FieldInfo; begin if T.IsPrimitive or T.IsEnum then exit; if T = typeof(TypedSet) then begin //TODO: обработать множества raise new CanNotUseTypeForFilesException(T); end; if T = typeof(string) then if FileIsBinary then exit else raise new CanNotUseTypeForTypedFilesException(T); if T.IsValueType then begin fields := T.GetFields(); foreach var fi in fields do if not fi.IsStatic then CheckCanUseTypeForFiles(fi.FieldType, FileIsBinary); exit; end; raise new CanNotUseTypeForFilesException(T); end; procedure CheckCanUseTypeForBinaryFiles(T: System.Type); begin CheckCanUseTypeForFiles(T, true); end; procedure CheckCanUseTypeForTypedFiles(T: System.Type); begin CheckCanUseTypeForFiles(T, false); end; function RuntimeDetermineType(T: System.Type): byte; begin result := 0; if T.IsValueType and (T.GetMethod('$Init$') <> nil) then begin result := 1; exit; end; if T = typeof(string) then begin result := 2; exit; end; if T = typeof(TypedSet) then begin result := 3; exit; end; if T = typeof(Text) then begin result := 4; exit; end; if T = typeof(BinaryFile) then begin result := 5; exit; end; end; function RuntimeInitialize(kind: byte; variable: object): object; begin case kind of 1: begin variable.GetType.InvokeMember('$Init$', System.Reflection.BindingFlags.InvokeMethod or System.Reflection.BindingFlags.Instance or System.Reflection.BindingFlags.Public, nil, variable, nil); result := variable; end; 2: result := ''; 3: result := new TypedSet; 4: result := new Text; 5: result := new BinaryFile; end; end; function GetRuntimeSize: integer; var val: T; begin result := System.Runtime.InteropServices.Marshal.SizeOf(val); end; // Функции для новых множеств var _emptyset: EmptyCollection := new EmptyCollection; type SetCreatorFunctionAttribute = class(Attribute) end; function EmptySet := _emptyset; [SetCreatorFunction] function __NewSetCreatorInternal(params a: array of T): NewSet; begin //Result._hs := new HashSet; Result._hs.UnionWith(a); end; [SetCreatorFunction] function __NSetInteger(a: array of integer; dd: array of integer): NewSet; begin Result._hs.UnionWith(a); var n := dd.Length; for var i:=0 to n-1 step 2 do begin for var j := dd[i] to dd[i+1] do Result.Add(j); end end; [SetCreatorFunction] function __NSetChar(a: array of char; dd: array of char): NewSet; begin Result._hs.UnionWith(a); var n := dd.Length; for var i:=0 to n-1 step 2 do begin for var j := dd[i] to dd[i+1] do Result.Add(j); end end; [SetCreatorFunction] function __NSetBoolean(a: array of boolean; dd: array of boolean): NewSet; begin Result._hs.UnionWith(a); var n := dd.Length; for var i:=0 to n-1 step 2 do begin for var j := dd[i] to dd[i+1] do Result.Add(j); end end; [SetCreatorFunction] function __NSetEnum(a: array of T; dd: array of T): NewSet; begin Result._hs.UnionWith(a); var vals := System.Enum.GetValues(typeof(T)).Cast&.ToArray; var n := dd.Length; for var i:=0 to n-1 step 2 do begin var ind1 := vals.IndexOf(dd[i]); var ind2 := vals.IndexOf(dd[i+1]); for var j := ind1 to ind2 do Result.Add(T(vals[j])); end end; function operator implicit(a: array of T): HashSet; extensionmethod := new HashSet(a); function operator implicit(a: array of integer): HashSet; extensionmethod := new HashSet(a); // ----------------------------------------------------------------------------- // Внутренние вспомогательные функции // ----------------------------------------------------------------------------- function get_sizes(a: &Array): array of integer; begin var rank := a.Rank; Result := Result; SetLength(Result, rank); for var i := 0 to rank - 1 do Result[i] := a.GetLength(i); end; procedure internal_copy(source, dest: &Array; source_sizes, dest_sizes: array of integer; i: integer; var src_ind, dest_ind: integer; flag: byte); begin if i <> source_sizes.Length - 1 then begin for var j := 0 to min(source_sizes[i], dest_sizes[i]) - 1 do internal_copy(source, dest, source_sizes, dest_sizes, i + 1, src_ind, dest_ind, flag); if dest_sizes[i] > source_sizes[i] then for var j := source_sizes[i] to dest_sizes[i] - 1 do begin internal_copy(source, dest, source_sizes, dest_sizes, i + 1, src_ind, dest_ind, 1); end else if dest_sizes[i] < source_sizes[i] then for var j := dest_sizes[i] to source_sizes[i] - 1 do begin internal_copy(source, dest, source_sizes, dest_sizes, i + 1, src_ind, dest_ind, 2); end end else begin if flag = 0 then begin System.Array.Copy(source, src_ind, dest, dest_ind, min(source_sizes[source_sizes.Length - 1], dest_sizes[source_sizes.Length - 1])); src_ind += source_sizes[source_sizes.Length - 1]; dest_ind += dest_sizes[source_sizes.Length - 1]; end else if flag = 1 then dest_ind += dest_sizes[source_sizes.Length - 1] else src_ind += source_sizes[source_sizes.Length - 1]; end; end; function CopyWithSize(source, dest: &Array): &Array; begin if source <> nil then begin //System.Array.Copy(source,dest,min(source.Length,dest.Length)); var source_sizes := get_sizes(source); var dest_sizes := get_sizes(dest); var src_ind := 0; var dest_ind := 0; internal_copy(source, dest, source_sizes, dest_sizes, 0, src_ind, dest_ind, 0); end; Result := dest; end; {function TypedSetComparer.Equals(x: System.Object; y: System.Object): boolean; begin //Result := object.Equals(x,y); Result := object.Equals(x, y); if not Result then begin var left_type := x.GetType; var right_type := y.GetType; case System.Type.GetTypeCode(left_type) of TypeCode.Byte: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.SByte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int32: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.SByte: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.SByte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int32: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.UInt16: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.SByte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int32: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.Int16: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.SByte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int32: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.Int32: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.SByte: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt16: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.Int32: Result := Convert.ToInt32(x) = Convert.ToInt32(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.UInt32: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.SByte: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int16: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt16: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.Int64: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.SByte: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int16: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt16: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt32: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; TypeCode.UInt64: begin case System.Type.GetTypeCode(right_type) of TypeCode.Byte: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.SByte: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.Int16: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.UInt16: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.Int32: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.UInt32: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.Int64: Result := Convert.ToUInt64(x) = Convert.ToInt64(y); TypeCode.UInt64: Result := Convert.ToUInt64(x) = Convert.ToUInt64(y); end; end; end; end; end; function TypedSetComparer.GetHashCode(obj: System.Object): integer; begin case System.Type.GetTypeCode(obj.GetType) of TypeCode.Byte: Result := Convert.ToByte(obj); TypeCode.SByte: Result := Convert.ToSByte(obj); TypeCode.UInt16: Result := Convert.ToUInt16(obj); TypeCode.Int16: Result := Convert.ToInt16(obj); TypeCode.Int32: Result := Convert.ToInt32(obj); TypeCode.UInt32: Result := Convert.ToUInt32(obj).GetHashCode(); TypeCode.Int64: Result := Convert.ToInt64(obj).GetHashCode(); TypeCode.UInt64: Result := Convert.ToUInt64(obj).GetHashCode(); else Result := obj.GetHashCode(); end; end;} var __from_dll := false; function ExecuteAssemlyIsDll: boolean; begin Result := not __from_dll and (System.IO.Path.GetExtension(System.Reflection.Assembly.GetExecutingAssembly.ManifestModule.FullyQualifiedName).ToLower = '.dll'); end; function IsUnix: boolean; begin Result := (Environment.OSVersion.Platform = PlatformID.Unix) or (Environment.OSVersion.Platform = PlatformID.MacOSX); end; function __StandardFilesDirectory: string; begin // Грубо. Исправить, сделав поиск Result := 'C:\Program Files (x86)\PascalABC.NET\Files\'; end; function __FindFile(fileName: string): string; begin Result := __StandardFilesDirectory+fileName; if not FileExists(Result) then Result := ''; if Result = '' then Result := fileName; if not FileExists(Result) then Result := ''; end; function InternalRange(l,r: integer): IntRange := new IntRange(l,r); function InternalRange(l,r: char): CharRange := new CharRange(l,r); function InternalRange(l,r: real): RealRange := new RealRange(l,r); //------------------------------------------------------------------------------ //OMP procedure omp_set_nested(nested: integer); begin OMP_NESTED := nested <> 0; end; function omp_get_nested: integer; begin if OMP_NESTED then result := 1 else result := 0; end; type NotPinnableWrapper = class [ThreadStatic] static notPinnableTypes: HashSet<&Type>; end; // ----------------------------------------------------- // Internal procedures for PABCRTL.dll: implementation // ----------------------------------------------------- var __initialized := false; [System.Diagnostics.DebuggerStepThrough] function __FixPointer(obj: object): GCHandle; begin if obj <> nil then begin try if (NotPinnableWrapper.notPinnableTypes <> nil) and NotPinnableWrapper.notPinnableTypes.Contains(obj.GetType()) then Result := GCHandle.Alloc(obj) else Result := GCHandle.Alloc(obj, GCHandleType.Pinned); except if NotPinnableWrapper.notPinnableTypes = nil then NotPinnableWrapper.notPinnableTypes := new HashSet<&Type>; NotPinnableWrapper.notPinnableTypes.Add(obj.GetType()); Result := GCHandle.Alloc(obj); end; end; end; procedure __InitModule; begin try DefaultEncoding := Encoding.GetEncoding(1251); except //DefaultEncoding := Encoding.UTF8; DefaultEncoding := new System.Text.UTF8Encoding(false) end; try if (System.Environment.OSVersion.Version.Major >= 6) and (System.Environment.OSVersion.Version.Minor >= 2) then System.Console.OutputEncoding := new System.Text.UTF8Encoding(false); //System.Console.OutputEncoding := Encoding.UTF8; except end; rnd := new System.Random; CurrentIOSystem := new IOStandardSystem; var locale: object; var locale_str := 'ru-RU'; if __CONFIG__.TryGetValue('full_locale', locale) then locale_str := string(locale); System.Threading.Thread.CurrentThread.CurrentUICulture := System.Globalization.CultureInfo.GetCultureInfo(locale_str); nfi := new System.Globalization.NumberFormatInfo(); nfi.NumberGroupSeparator := '.'; {var ci := System.Globalization.CultureInfo.GetCultureInfo(locale_str); ci.NumberFormat.NumberDecimalSeparator := '.'; System.Threading.Thread.CurrentThread.CurrentCulture := ci; System.Threading.Thread.CurrentThread.CurrentUICulture := ci;} // SSM 1.08.18 только в текущем потоке будет точка в вещественных // В Net 4.6 System.Globalization.CultureInfo.DefaultThreadCurrentCulture := ci // Но как сделать чтобы работало и в младших NET - не знаю //var ci := (System.Globalization.CultureInfo.CurrentCulture.Clone as System.Globalization.CultureInfo); //ci.NumberFormat := nfi; //System.Globalization.CultureInfo.CurrentCulture := ci; // SSM 10/11/18 восстановил эту строку чтобы в главном потоке в вещественных была точка System.Threading.Thread.CurrentThread.CurrentCulture := new System.Globalization.CultureInfo('en-US'); var defaultCulture := typeof(System.Globalization.CultureInfo).GetProperty('DefaultThreadCurrentCulture'); if defaultCulture <> nil then defaultCulture.SetValue(nil, new System.Globalization.CultureInfo('en-US'), nil); input := new TextFile(); output := new TextFile(); output.sw := Console.Out; ErrOutput := new TextFile(); ErrOutput.sw := Console.Error; {if (Environment.OSVersion.Platform = PlatformID.Unix) or (Environment.OSVersion.Platform = PlatformID.MacOSX) then foreach var listener in System.Diagnostics.Trace.Listeners do if listener is System.Diagnostics.DefaultTraceListener then (listener as System.Diagnostics.DefaultTraceListener).AssertUiEnabled := true; } __FixPointer(nil); StartTime := DateTime.Now; end; procedure __InitModule__; begin if not __initialized then begin __initialized := true; __from_dll := true; __InitModule; end; end; procedure __InitPABCSystem; begin __InitModule__; end; procedure __FinalizeModule__; begin if (output.sw <> nil) and (output.sw is StreamWriter) and ((output.sw as StreamWriter).BaseStream <> nil) then output.sw.Close; if (ErrOutput.sw <> nil) and (ErrOutput.sw is StreamWriter) and ((ErrOutput.sw as StreamWriter).BaseStream <> nil) then ErrOutput.sw.Close; if (input.sr <> nil) and (input.sr.BaseStream <> nil) then input.sr.Close; end; // ----------------------------------------------------- // DQNToNullable for dot_question_node: implementation // ----------------------------------------------------- function DQNToNullable(v: T): System.Nullable; where T: record; begin Result := new System.Nullable(v); end; initialization __InitModule; finalization __FinalizeModule__; end.