Пример #1
0
        public static ListRand Deserealize(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return(new ListRand());         // deserialization of empty lists
            }
            var serializedNodes = str.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            var map = new Dictionary <string, ValueTuple <string, string, string, string> >(); // using ValueTuple just because it is not required to write generic serializer

            foreach (var serializedNode in serializedNodes)
            {
                var parts = serializedNode.Split(new[] { _delim }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length < 5)
                {
                    // let's just throw an exception and write a good unit test
                    throw new InvalidDataException("There are less parts in serialization data than we expect");
                }

                // at some moment we will use more memory than we really need, optimisation isn't performed
                var id      = parts[0].Split(_sep)[1];
                var data    = StringsEscaper.UnEscape(parts[1].Split(_sep)[1]);
                var rndIdx  = parts[2].Split(_sep)[1];
                var prevIdx = parts[3].Split(_sep)[1];
                var nextIdx = parts[4].Split(_sep)[1];

                map[id] = (data, rndIdx, prevIdx, nextIdx);
            }

            var lst           = new ListRand();
            var restoredNodes = new Dictionary <string, ListNode>();
            var restoredNode  = new ListNode();

            foreach (var kv in map)
            {
                restoredNode      = RestoreNode(kv.Key, map, restoredNodes);
                restoredNode.Rand = RestoreNode(kv.Value.Item2, map, restoredNodes);
                restoredNode.Prev = RestoreNode(kv.Value.Item3, map, restoredNodes);
                restoredNode.Next = RestoreNode(kv.Value.Item4, map, restoredNodes);
            }


            lst.Head = restoredNode;
            while (lst.Head.Next != null) // guess we can get rid of this, but as there is no requirement of high performance, no optimisation performed
            {
                lst.Head = lst.Head.Next;
            }

            lst.Tail = lst.Head.Prev;

            lst.Count = map.Count;

            return(lst);
        }
Пример #2
0
        private string FormatNode(ListNode node)
        {
            int idx;

            if (!_objectToIndex.TryGetValue(node, out idx))
            {
                idx = _index += 1;
                _objectToIndex[node] = idx;
            }
            else // oh, we already have this value, must be referenced before
            {
                return(_objectToString[node]);
            }

            int rndIdx = 0;

            if (node.Rand != null)
            {
                if (!_objectToIndex.TryGetValue(node.Rand, out rndIdx))
                {
                    FormatNode(node.Rand); // okay, we have recursion here and can f**k everything up; we can solve this, but it's a trade-off and without clear requiriments this optimisation is premature
                    _objectToIndex.TryGetValue(node.Rand, out rndIdx);
                }
            }

            int prevIdx = 0;

            if (node.Prev != null) // as I don't know implementation of Add method, I assume that Prev could be null
            {
                if (!_objectToIndex.TryGetValue(node.Prev, out prevIdx))
                {
                    FormatNode(node.Prev);
                    _objectToIndex.TryGetValue(node.Prev, out prevIdx);
                }
            }

            int nextIdx = 0;

            if (node.Next != null) // as I don't know implementation of Add method, I assume that Next could be null
            {
                if (!_objectToIndex.TryGetValue(node.Next, out nextIdx))
                {
                    FormatNode(node.Next);
                    _objectToIndex.TryGetValue(node.Next, out nextIdx);
                }
            }

            // using of predefined ID, DATA, RAND, etc field names is more safier than using actual names of fields, as they could changed with time and broke back compatibility
            string result = $"ID{_sep}{idx}{_delim}DATA{_sep}{StringsEscaper.Escape(node.Data)}{_delim}RAND{_sep}{rndIdx}{_delim}PREV{_sep}{prevIdx}{_delim}NEXT{_sep}{nextIdx}";

            _objectToString[node] = result;

            return(result);
        }