Ejemplo n.º 1
0
        private void Sort(long start, long number, KeyString keyfunction)
        {
            PTypeSequence pts = (PTypeSequence)typ;

            if (number < 2)
            {
                return;             // сортировать не нужно
            }
            if (number < 10000000)
            {
                // Указатель на начальный элемент и размер головы записи
                PxEntry e    = this.Element(start);
                long    p0   = e.offset;
                int     size = pts.ElementType.HeadSize;
                // организуем массивы ключей и индексов - номеров записей
                string[] keys    = new string[number];
                int[]    indexes = Enumerable.Range(0, (int)number).ToArray();
                // Вычислим и запишем ключи

                for (long ii = 0; ii < number; ii++)
                {
                    keys[ii]  = keyfunction(e);
                    e.offset += size;
                }
                // Сортируем два массива
                Array.Sort(keys, indexes);
                ReorderSequenceArrayHeads(number, p0, size, indexes);
            }
            else
            {
            }
        }
Ejemplo n.º 2
0
        // В случае неудачи, возвращает PxEntry со значением поля offset == long.MinValue
        // Элемент elementFrom уже проверенный и меньше 0
        private static PxEntry BSF(PxEntry elementFrom, long number, Func <PxEntry, int> elementDepth)
        {
            long half = number / 2;

            if (half == 0)
            {
                return(new PxEntry(null, long.MinValue, null));           // Не найден
            }
            var     factor       = elementFrom.typ.HeadSize;
            PxEntry middle       = new PxEntry(elementFrom.typ, elementFrom.offset + half * factor, elementFrom.fis);
            var     middle_depth = elementDepth(middle);

            if (middle_depth == 0)
            {
                return(middle);
            }
            if (middle_depth < 0)
            {
                return(BSF(middle, number - half, elementDepth));
            }
            else
            {
                return(BSF(elementFrom, half, elementDepth));
            }
        }
Ejemplo n.º 3
0
        public PxEntry BinarySearchFirst(Func <PxEntry, int> elementDepth)
        {
            PxEntry sequ = this;
            var     typ  = sequ.typ;

            if (typ.Vid != PTypeEnumeration.sequence)
            {
                throw new Exception("Function FindZero can't be applied to the type with vid=" + typ.Vid);
            }
            PTypeSequence mts  = (PTypeSequence)sequ.typ;
            PType         tel  = mts.ElementType;
            long          llen = sequ.Count();

            if (llen == 0)
            {
                throw new Exception("No elements to FindZero");
            }
            var first_el    = sequ.Element(0);
            var first_depth = elementDepth(first_el);

            if (first_depth == 0)
            {
                return(first_el);
            }
            PxEntry found = BSF(first_el, llen, elementDepth);

            //if (found.offset == long.MinValue) throw new Exception("Zero element did't foound by FindZero()");
            return(found);
        }
Ejemplo n.º 4
0
        // Ищет все решения имея ввиду, что справа решения есть
        private static IEnumerable <PxEntry> BinarySearchLeft(PxEntry elementFrom, long number, Func <PxEntry, int> elementDepth)
        {
            long half = number / 2;

            if (half > 0)
            {
                var     size         = elementFrom.typ.HeadSize;
                PxEntry middle       = new PxEntry(elementFrom.typ, elementFrom.offset + half * size, elementFrom.fis);
                PxEntry aftermiddle  = new PxEntry(elementFrom.typ, middle.offset + size, elementFrom.fis);
                var     middle_depth = elementDepth(middle);

                if (middle_depth == 0)
                {
                    foreach (var pe in BinarySearchLeft(elementFrom, half, elementDepth))
                    {
                        yield return(pe);
                    }
                    yield return(middle);

                    // Переписать все из второй половины
                    for (long ii = 0; ii < number - half - 1; ii++)
                    {
                        yield return(aftermiddle);

                        aftermiddle = new PxEntry(elementFrom.typ, aftermiddle.offset + size, elementFrom.fis);
                    }
                }
                else if (middle_depth < 0)
                {
                    foreach (var pe in BinarySearchLeft(aftermiddle, number - half - 1, elementDepth))
                    {
                        yield return(pe);
                    }
                }
                else
                {
                    throw new Exception("Assert err: 9283");
                }
            }
            else if (number == 1) // возможно одно решение или их нет
            {
                if (elementDepth(elementFrom) == 0)
                {
                    yield return(elementFrom);
                }
            }
        }
Ejemplo n.º 5
0
        // Ищет все решения внутри имея ввиду, что слева за диапазоном уровень меньше нуля, справа за диапазоном больше
        private static IEnumerable <PxEntry> BinarySearchInside(PxEntry elementFrom, long number, Func <PxEntry, int> elementDepth)
        {
            long half = number / 2;

            if (half > 0)
            {
                var     size         = elementFrom.typ.HeadSize;
                PxEntry middle       = new PxEntry(elementFrom.typ, elementFrom.offset + half * size, elementFrom.fis);
                PxEntry aftermiddle  = new PxEntry(elementFrom.typ, middle.offset + size, elementFrom.fis);
                var     middle_depth = elementDepth(middle);

                if (middle_depth == 0)
                {
                    foreach (var pe in BinarySearchLeft(elementFrom, half, elementDepth))
                    {
                        yield return(pe);
                    }
                    yield return(middle);

                    foreach (var pe in BinarySearchRight(aftermiddle, number - half - 1, elementDepth))
                    {
                        yield return(pe);
                    }
                }
                else if (middle_depth < 0)
                {
                    foreach (var pe in BinarySearchInside(aftermiddle, number - half - 1, elementDepth))
                    {
                        yield return(pe);
                    }
                }
                else // if (middle_depth > 0)
                {
                    foreach (var pe in BinarySearchInside(elementFrom, half, elementDepth))
                    {
                        yield return(pe);
                    }
                }
            }
            else if (number == 1) // возможно одно решение или их нет
            {
                if (elementDepth(elementFrom) == 0)
                {
                    yield return(elementFrom);
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Метод реализует сортировку, т.е. перестановку элементов последовательности в соотвествии с функцией
        /// сравнения, заданной аргументом
        /// </summary>
        /// <param name="compare">Функция, задающая сравнение друх входов</param>
        public void SortComparison(System.Comparison <PxEntry> compare)
        {
            if (typ.Vid != PTypeEnumeration.sequence)
            {
                throw new Exception("SortComparison can't be implemented to this vid");
            }
            PTypeSequence pts  = (PTypeSequence)typ;
            long          llen = this.Count();

            if (llen < 2)
            {
                return;           // сортировать не нужно
            }
            // Указатель на нулевой элемент и размер головы записи
            long p0   = this.Element(0).offset;
            int  size = pts.ElementType.HeadSize;

            // организуем массив offset'ов - указателей на головы элементов
            long[] offsets = new long[llen];
            for (long ind = 0; ind < llen; ind++)
            {
                offsets[ind] = p0 + size * ind;
            }
            //теперь сортируем используя функцию сравнения
            PxEntry e1 = new PxEntry(pts.ElementType, long.MinValue, this.fis);
            PxEntry e2 = new PxEntry(pts.ElementType, long.MinValue, this.fis);

            Array.Sort <long>(offsets, (long o1, long o2) =>
            {
                e1.offset = o1;
                e2.offset = o2;
                return(compare(e1, e2));
            });
            // Надеюсь, отсортировали

            // Превращаю массив смещений в массив индексов элементов
            int[] indexes = new int[llen];
            for (long ind = 0; ind < llen; ind++)
            {
                indexes[ind] = (int)((offsets[ind] - p0) / size);
            }
            // теперь в i-ом элементе массива находится индекс элемента (головы), который должен попасть на i-ю позицию
            ReorderSequenceArrayHeads(llen, p0, size, indexes);
        }
Ejemplo n.º 7
0
        // Ищет все решения имея ввиду, что слева решения есть
        private static IEnumerable <PxEntry> BinarySearchRight(PxEntry elementFrom, long number, Func <PxEntry, int> elementDepth)
        {
            long half = number / 2;

            if (half > 0)
            {
                var     size         = elementFrom.typ.HeadSize;
                PxEntry middle       = new PxEntry(elementFrom.typ, elementFrom.offset + half * size, elementFrom.fis);
                PxEntry aftermiddle  = new PxEntry(elementFrom.typ, middle.offset + size, elementFrom.fis);
                var     middle_depth = elementDepth(middle);

                if (middle_depth == 0)
                {
                    // Переписать все из первой половины
                    PxEntry ef = elementFrom;
                    for (long ii = 0; ii < half; ii++)
                    {
                        yield return(ef);

                        ef = new PxEntry(elementFrom.typ, ef.offset + size, elementFrom.fis);
                    }
                    yield return(middle);

                    foreach (var pe in BinarySearchRight(aftermiddle, number - half - 1, elementDepth))
                    {
                        yield return(pe);
                    }
                }
                else if (middle_depth > 0)
                {
                    foreach (var pe in BinarySearchRight(elementFrom, half, elementDepth))
                    {
                        yield return(pe);
                    }
                }
            }
            else if (number == 1) // возможно одно решение или их нет
            {
                if (elementDepth(elementFrom) == 0)
                {
                    yield return(elementFrom);
                }
            }
        }
Ejemplo n.º 8
0
        public IEnumerable <PxEntry> BinarySearchAll(Func <PxEntry, int> elementDepth)
        {
            PxEntry sequ = this;
            var     typ  = sequ.typ;

            if (typ.Vid != PTypeEnumeration.sequence)
            {
                throw new Exception("Function FindZero can't be applied to the type with vid=" + typ.Vid);
            }
            PTypeSequence mts  = (PTypeSequence)sequ.typ;
            PType         tel  = mts.ElementType;
            long          llen = sequ.Count();

            if (llen > 0)
            {
                var elementFrom = sequ.Element(0);
                foreach (var pe in BinarySearchInside(elementFrom, llen, elementDepth))
                {
                    yield return(pe);
                }
            }
        }
Ejemplo n.º 9
0
        private void MergeUp(long start, long number1, long number2, KeyString keyfunction)
        {
            if (number1 == 0 || number2 == 0)
            {
                return;
            }
            PTypeSequence pts  = (PTypeSequence)typ;
            int           size = pts.ElementType.HeadSize;
            // Заведем файл для верхнего массива
            string tmp_name = "../../../Databases/temp.bin";

            System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000);
            // Cкопируем нужное число байтов
            int buff_size = 8192;

            byte[]  buffer  = new byte[buff_size];
            PxEntry entry1  = this.Element(start);
            long    pointer = entry1.offset;

            this.fis.SetOffset(pointer);
            long bytestocopy = number1 * size;

            while (bytestocopy > 0)
            {
                int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size);
                tmp.Write(buffer, 0, nb);
                bytestocopy -= nb;
            }
            // Вычислим и запомним во временной ячейке ключи массива 1.
            // сначала тип ячейки и ячейка:
            PType  tp_tmp        = new PType(PTypeEnumeration.sstring);
            string tmp_cell_name = "../../../Databases/tmp.pac";
            PaCell tmp_cell      = new PaCell(tp_tmp, tmp_cell_name, false);

            // теперь заполним ее значениями
            //tmp_cell.StartSerialFlow();
            //tmp_cell.S();
            //for (long ii=0; ii<number1; ii++)
            //{
            //    string key = keyfunction(entry1);
            //    tmp_cell.V(key);
            //    entry1.offset += size;
            //}
            //tmp_cell.Se();
            //tmp_cell.EndSerialFlow();
            tmp_cell.Fill(new object[0]);
            for (long ii = 0; ii < number1; ii++)
            {
                string key = keyfunction(entry1);
                tmp_cell.Root.AppendElement(key);
                entry1.offset += size;
            }
            tmp_cell.Flush();
            // теперь будем сливать массивы
            tmp.Position = 0L; // в файле tmp
            long pointer2   = pointer + number1 * size;
            long tmp_offset = tmp_cell.Root.Element(0).offset;

            tmp_cell.SetOffset(tmp_offset);
            PType   tp_sstring = new PType(PTypeEnumeration.sstring);
            string  key1       = (string)tmp_cell.ScanObject(tp_sstring);
            long    cnt1       = 1; // число прочитанных элементов первой подпоследовательности
            PxEntry entry2     = this.Element(start + number1);
            string  key2       = keyfunction(entry2);
            long    cnt2       = 1; // число прочитанных элементов второй подпоследовательности

            byte[] buff_el  = new byte[size * 8192];
            int    buff_pos = 0;

            while (cnt1 > number1 || cnt2 > number2)
            {
                if (key1.CompareTo(key2) < 0)
                { // Продвигаем первую подпоследовательность
                    tmp.Read(buff_el, buff_pos, size); buff_pos += size;
                    key1 = (string)tmp_cell.ScanObject(tp_sstring);
                    cnt1++;
                }
                else
                { // Продвигаем вторую последовательность
                    entry2.fis.SetOffset(entry2.offset);
                    entry2.fis.fs.Read(buff_el, buff_pos, size); buff_pos += size;
                    entry2.offset += size;
                    key2           = keyfunction(entry2);
                    cnt2++;
                }
            }
            // Теперь надо переписать остатки
        }
Ejemplo n.º 10
0
        private void MergeUp <T>(long start, long number1, long number2, Func <PxEntry, T> keyfunction)
        {
            if (number1 == 0 || number2 == 0)
            {
                return;
            }
            PTypeSequence pts      = (PTypeSequence)typ;
            int           size     = pts.ElementType.HeadSize;
            string        tmp_name = "../../../Databases/temp.bin";

            System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000);
            // Cкопируем нужное число байтов
            int buff_size = 8192;

            byte[]  buffer  = new byte[buff_size];
            PxEntry entry1  = this.Element(start);
            long    pointer = entry1.offset;

            this.fis.SetOffset(pointer);
            long bytestocopy = number1 * size;

            while (bytestocopy > 0)
            {
                int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size);
                tmp.Write(buffer, 0, nb);
                bytestocopy -= nb;
            }
            // Вычислим и запомним во временной ячейке ключи массива 1.
            // сначала тип ячейки и ячейка:
            PxEntry     entry2 = this.Element(start + number1); // Это понадобится в будущем, а пока используем для определения типа ключа
            IComparable key2   = (IComparable)keyfunction(entry2);
            PType       tp_key = key2 is string?new PType(PTypeEnumeration.sstring) :
                                     (key2 is int?new PType(PTypeEnumeration.integer) :
                                          (key2 is long?new PType(PTypeEnumeration.longinteger) :
                                               (key2 is byte?new PType(PTypeEnumeration.@byte) :
                                                    (key2 is double?new PType(PTypeEnumeration.real) : null))));

            PType  tp_tmp        = new PTypeSequence(tp_key);
            string tmp_cell_name = "../../../Databases/tmp.pac"; //TODO: Надо имя файла генерировать, а то могут быть коллизии
            PaCell tmp_cell      = new PaCell(tp_tmp, tmp_cell_name, false);

            // теперь заполним ее значениями
            //tmp_cell.StartSerialFlow();
            //tmp_cell.S();
            //for (long ii = 0; ii < number1; ii++)
            //{
            //    var key = keyfunction(entry1);
            //    tmp_cell.V(key);
            //    entry1.offset += size;
            //}
            //tmp_cell.Se();
            //tmp_cell.EndSerialFlow();
            tmp_cell.Fill(new object[0]);
            for (long ii = 0; ii < number1; ii++)
            {
                var key = keyfunction(entry1);
                tmp_cell.Root.AppendElement(key);
                entry1.offset += size;
            }
            tmp_cell.Flush();
            // теперь будем сливать массивы
            tmp.Position = 0L; // в файле tmp
            long pointer2   = pointer + number1 * size;
            long tmp_offset = tmp_cell.Root.Element(0).offset;

            tmp_cell.SetOffset(tmp_offset);
            //PType tp_sstring = new PType(PTypeEnumeration.sstring);
            IComparable key1 = (IComparable)tmp_cell.ScanObject(tp_key);
            long        cnt1 = 0; // число переписанных элементов первой подпоследовательности
            //PxEntry entry2 = this.Element(start + number1);
            //var key2 = keyfunction(entry2); // Уже прочитан
            long cnt2 = 0; // число переписанных элементов второй подпоследовательности

            byte[] buff     = new byte[size * 8192];
            int    buff_pos = 0;

            while (cnt1 == number1 || cnt2 == number2)
            {
                if (key1.CompareTo(key2) < 0)
                { // Продвигаем первую подпоследовательность
                    tmp.Read(buff, buff_pos, size); buff_pos += size;
                    cnt1++;
                    if (cnt1 < number1)
                    {
                        key1 = (IComparable)tmp_cell.ScanObject(tp_key);                 // Возможен конец
                    }
                }
                else
                { // Продвигаем вторую последовательность
                    entry2.fis.SetOffset(pointer2);
                    pointer2 += size;
                    entry2.fis.fs.Read(buff, buff_pos, size); buff_pos += size;
                    cnt2++;
                    if (cnt2 < number2)
                    {
                        key2 = (IComparable)keyfunction(entry2);                 // Возможен конец
                    }
                }
                // Если буфер заполнился, его надо сбросить
                if (buff_pos == buff.Length)
                {
                    this.fis.SetOffset(pointer);
                    this.fis.fs.Write(buff, 0, buff_pos);
                    pointer += buff_pos;
                    buff_pos = 0;
                }
            }
            // Теперь надо переписать остатки
            if (cnt1 < number1)
            {
                this.fis.SetOffset(pointer); // Здесь запись ведется подряд, без перемещений головки чтения/записи
                bytestocopy = (number1 - cnt1) * size;
                while (bytestocopy > 0)
                {
                    int nbytes = buff.Length - buff_pos;
                    if (bytestocopy < nbytes)
                    {
                        nbytes = (int)bytestocopy;
                    }
                    tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes;
                    this.fis.fs.Write(buff, 0, buff_pos);
                    buff_pos = 0;
                }
            }
            else if (cnt2 < number2)
            {
                bytestocopy = (number2 - cnt2) * size;
                while (bytestocopy > 0)
                {
                    int nbytes = buff.Length - buff_pos;
                    if (bytestocopy < nbytes)
                    {
                        nbytes = (int)bytestocopy;
                    }
                    this.fis.SetOffset(pointer2); //TODO: Здесь вроде я не то беру, надо разобраться (2 строчки ниже!)
                    pointer2 += nbytes;
                    tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes;
                    this.fis.SetOffset(pointer);
                    this.fis.fs.Write(buff, 0, buff_pos);
                    pointer += buff_pos;
                    buff_pos = 0;
                }
            }
        }
Ejemplo n.º 11
0
        public void Set(object valu)
        {
            // Возможно, стоит убрать следующую установку и внести ее в варианты, этого требующие
            fis.SetOffset(this.offset);
            switch (typ.Vid)
            {
            case PTypeEnumeration.none: break;

            case PTypeEnumeration.boolean: fis.bw.Write((bool)valu); break;

            case PTypeEnumeration.character:
            {
                char ch = (char)valu;
                var  cc = ch - '\0';
                //char.ConvertToUtf32(
                fis.bw.Write((ushort)cc);
                break;
            }

            case PTypeEnumeration.integer: fis.bw.Write((int)valu); break;

            case PTypeEnumeration.longinteger: fis.bw.Write((long)valu); break;

            case PTypeEnumeration.real: fis.bw.Write((double)valu); break;

            case PTypeEnumeration.@byte: fis.bw.Write((byte)valu); break;

            case PTypeEnumeration.fstring:
            {
                string s    = (string)valu;
                int    size = ((PTypeFString)typ).Size;
                byte[] arr  = new byte[size];
                if (s.Length * 2 > size)
                {
                    s = s.Substring(0, size / 2);
                }
                var qu = System.Text.Encoding.Unicode.GetBytes(s, 0, s.Length, arr, 0);
                fis.bw.Write(arr);
            }
            break;

            case PTypeEnumeration.sstring:
            {
                string s   = (string)valu;
                int    len = s.Length;
                fis.bw.Write(len);
                if (len > 0)
                {
                    long off = this.fis.freespace;
                    this.fis.freespace += 2 * len;
                    fis.bw.Write(off);
                    //vtoList.Enqueue(new VTO(valu, typ, off)); // Вместо "метания" записи, стоит использовать очередь или что-то подбное
                    byte[] bytes = Encoding.Unicode.GetBytes(s);
                    if (bytes.Length != s.Length * 2)
                    {
                        throw new Exception("Assert Error in Set(string)");
                    }
                    fis.SetOffset(off);
                    fis.bw.Write(bytes);
                }
            }
            break;

            case PTypeEnumeration.record:
            {
                PTypeRecord mtr = (PTypeRecord)typ;
                object[]    arr = (object[])valu;
                if (arr.Length != mtr.Fields.Length)
                {
                    throw new Exception("Err in Set(): record has wrong number of fields");
                }
                long field_offset = this.offset;
                for (int i = 0; i < arr.Length; i++)
                {
                    PxEntry entry = new PxEntry(mtr.Fields[i].Type, field_offset, this.fis);
                    //FillHead(arr[i], mtr.Fields[i].Type, vtoList);
                    entry.Set(arr[i]);
                    //if (i < arr.Length - 1) // Добавление не мешает, можно не проверять
                    field_offset += mtr.Fields[i].Type.HeadSize;
                }
            }
            break;

            case PTypeEnumeration.sequence:
            {
                PTypeSequence mts = (PTypeSequence)typ;
                PType         tel = mts.ElementType;
                // Пишем голову последовательности
                object[] arr  = (object[])valu;
                long     llen = arr.Length;

                // Внешний уровень определяем по позиции указателя
                if (this.offset == fis.dataStart)
                {
                    fis.nElements = llen;
                }

                fis.bw.Write(llen);
                // Следующие три оператора можно не делать для пустых последовательносте, но даст ли это экономию, неизвестно
                long off = fis.freespace;
                fis.bw.Write(0L);
                fis.bw.Write(off);
                // Если есть хвост, ставим в очередь
                //if (llen > 0) vtoList.Enqueue(new VTO(valu, typ, off));
                // Если есть элементы, заведем место, сформируем массив и запишем элементы
                if (llen > 0)
                {
                    int size = tel.HeadSize;
                    fis.freespace += size * llen;
                    PxEntry entry = new PxEntry(tel, off, fis);
                    for (long i = 0; i < llen; i++)
                    {
                        entry.Set(arr[i]);
                        entry.offset += size;
                    }
                }
            }
            break;

            case PTypeEnumeration.union:
            {
                object[]   arr = (object[])valu;
                int        tag = (int)arr[0];
                PTypeUnion mtu = (PTypeUnion)typ;
                PType      tel = mtu.Variants[tag].Type;
                // Пишем голову
                fis.bw.Write((byte)(int)arr[0]);
                if (tel.IsAtom)
                {
                    if (arr[1] == null)
                    {
                        fis.bw.Write(-1L);
                    }
                    else
                    {
                        fis.WriteAtomAsLong(tel.Vid, arr[1]);
                    }
                }
                else
                {
                    long off = fis.freespace;
                    fis.freespace += tel.HeadSize;
                    fis.bw.Write(off);
                    //vtoList.Enqueue(new VTO(arr[1], tel, off) { makehead = true });
                    PxEntry subelement = new PxEntry(tel, off, fis);
                    subelement.Set(arr[1]);
                }
            }
            break;

            default: throw new Exception("unexpected type");
            }
        }