Пример #1
0
 /// <summary>
 /// Construct a Table.
 /// </summary>
 public Table(int capacity = DefaultCapacity)
 {
     if (capacity <= 0)
     {
         throw new ArgumentException($"Capacity {capacity} must be >= 0");
     }
     SingleValues = new SpannableList <TValue>(capacity);
 }
Пример #2
0
 /// <summary>
 /// Construct a derived Table sharing the IDs of the given base Table.
 /// </summary>
 public Table(ITable <TId> baseTable)
 {
     if (baseTable == null)
     {
         throw new ArgumentException("Base table must not be null");
     }
     BaseTableOpt = baseTable;
     SingleValues = new SpannableList <TValue>(baseTable.Count == 0 ? DefaultCapacity : baseTable.Count);
 }
Пример #3
0
            /// <summary>
            /// All relationships have been added; sort them all and build the final relation table.
            /// </summary>
            public void Complete()
            {
                m_list.AsSpan().Sort((tuple1, tuple2) =>
                {
                    int fromIdCompare = tuple1.fromId.FromId().CompareTo(tuple2.fromId.FromId());
                    if (fromIdCompare != 0)
                    {
                        return(fromIdCompare);
                    }
                    return(tuple1.toId.FromId().CompareTo(tuple2.toId.FromId()));
                });

                // and bin them by groups
                int listIndex = 0;
                SpannableList <TToId> buffer = new SpannableList <TToId>();
                int listCount = m_list.Count;

                Table.SetMultiValueCapacity(listCount);

                foreach (TFromId id in Table.BaseTableOpt.Ids)
                {
                    if (listIndex >= m_list.Count)
                    {
                        // ran outta entries, rest all 0
                        break;
                    }

                    // Count up how many are for id.
                    int count = 0;
                    buffer.Clear();

                    // create a to-ID that will never equal any other ID (even default)
                    TToId lastToId = default(TToId).ToId(-1);

                    while (listIndex + count < m_list.Count)
                    {
                        var(fromId, toId) = m_list[listIndex + count];
                        if (fromId.Equals(id))
                        {
                            // drop duplicates (silently...)
                            // TODO: are duplicates here a logic bug? Because they do happen in practice.
                            if (!toId.Equals(lastToId))
                            {
                                buffer.Add(toId);
                            }
                            count++;
                            lastToId = toId;
                            continue;
                        }
                        // ok we're done
                        break;
                    }

                    Table.Add(buffer.AsSpan());
                    listIndex += count;
                }
            }
Пример #4
0
        /// <summary>
        /// Save this list of unmanaged values to the given filename in the given directory.
        /// </summary>
        public static void SaveToFile <TValue>(string directory, string name, SpannableList <TValue> values)
            where TValue : unmanaged
        {
            string path = Path.Combine(directory, name);

            using (Stream writer = File.OpenWrite(path))
            {
                // kind of a lot of work to write out an int, but whatevs
                int[] length = new int[] { values.Count };
                writer.Write(MemoryMarshal.Cast <int, byte>(new Span <int>(length)));

                writer.Write(MemoryMarshal.Cast <TValue, byte>(values.AsSpan()));
            }
        }
Пример #5
0
        /// <summary>
        /// Load a list of unmanaged values from the given filename in the given directory.
        /// </summary>
        public static void LoadFromFile <TValue>(string directory, string name, SpannableList <TValue> values)
            where TValue : unmanaged
        {
            values.Clear();

            string path = Path.Combine(directory, name);

            using (Stream reader = File.OpenRead(path))
            {
                int[] lengthBuf = new int[1];
                reader.Read(MemoryMarshal.Cast <int, byte>(new Span <int>(lengthBuf)));
                int length = lengthBuf[0];

                values.Capacity = length;
                values.Fill(length, default);

                Span <TValue> valueSpan     = values.AsSpan();
                Span <byte>   byteValueSpan = MemoryMarshal.Cast <TValue, byte>(valueSpan);
                reader.Read(byteValueSpan);
            }
        }
Пример #6
0
        /// <summary>
        /// Create a new RelationTable that is the inverse of this relation.
        /// </summary>
        /// <remarks>
        /// Very useful for calculating, for example, pip dependents based on pip dependencies, or
        /// per-file producers based on per-pip files produced.
        /// </remarks>
        public RelationTable <TToId, TFromId> Invert()
        {
            RelationTable <TToId, TFromId> result = new RelationTable <TToId, TFromId>(RelatedTable, BaseTableOpt);

            // We will use result.Values to accumulate the counts as usual.
            result.SingleValues.Fill(RelatedTable.Count, 0);
            // And we will use result.m_offsets to store the offsets as usual.
            result.Offsets.Fill(RelatedTable.Count, 0);

            int sum = 0;

            foreach (TFromId id in BaseTableOpt.Ids)
            {
                foreach (TToId relatedId in this[id])
                {
                    result.SingleValues[relatedId.FromId() - 1]++;
                    sum++;
                }
            }

            // Now we can calculate m_offsets.
            result.CalculateOffsets();

            // And we know the necessary size of m_relations.
            result.MultiValues.Capacity = sum;
            result.MultiValues.Fill(sum, default);

            // Allocate an array of positions to track how many relations we have filled in.
            SpannableList <int> positions = new SpannableList <int>(RelatedTable.Count + 1);

            positions.Fill(RelatedTable.Count + 1, 0);

            // And accumulate all the inverse relations.
            foreach (TFromId id in BaseTableOpt.Ids)
            {
                foreach (TToId relatedId in this[id])
                {
                    int relatedIdInt  = relatedId.FromId() - 1;
                    int idInt         = id.FromId() - 1;
                    int offset        = result.Offsets[relatedIdInt];
                    int position      = positions[relatedIdInt];
                    int relationIndex = result.Offsets[relatedIdInt] + positions[relatedIdInt];
                    result.MultiValues[relationIndex] = id;
                    positions[relatedIdInt]++;
                    if (positions[relatedIdInt] > result.SingleValues[relatedIdInt])
                    {
                        // this is a logic bug, should never happen
                        throw new Exception(
                                  $"RelationTable.Inverse: logic exception: positions[{relatedIdInt}] = {positions[relatedIdInt]}, result.SingleValues[{relatedIdInt}] = {result.SingleValues[relatedIdInt]}");
                    }
                    else if (positions[relatedIdInt] == result.SingleValues[relatedIdInt])
                    {
                        // all the relations for this ID are known. now, we have to sort them.
                        Span <TFromId> finalSpan =
                            result.MultiValues.AsSpan().Slice(result.Offsets[relatedIdInt], result.SingleValues[relatedIdInt]);
                        SpanUtilities.Sort(finalSpan, (id1, id2) => id1.FromId().CompareTo(id2.FromId()));
                    }
                }
            }

            // TODO: error check that there are no zero entries in m_relations

            return(result);
        }
Пример #7
0
 /// <summary>
 /// Construct a MultiValueTable.
 /// </summary>
 /// <remarks>
 /// This must be called after baseTable has been fully populated,
 /// or this table will not be able to preallocate its capacity.
 /// </remarks>
 public MultiValueTable(int capacity = DefaultCapacity) : base(capacity)
 {
     Offsets     = new SpannableList <int>(capacity);
     MultiValues = new SpannableList <TValue>();
 }
Пример #8
0
 /// <summary>
 /// Construct a MultiValueTable.
 /// </summary>
 /// <remarks>
 /// This must be called after baseTable has been fully populated,
 /// or this table will not be able to preallocate its capacity.
 /// </remarks>
 public MultiValueTable(ITable <TId> baseTable) : base(baseTable)
 {
     Offsets     = new SpannableList <int>(baseTable.Count == 0 ? DefaultCapacity : baseTable.Count);
     MultiValues = new SpannableList <TValue>();
 }