more work
This commit is contained in:
		
							parent
							
								
									c7539b028a
								
							
						
					
					
						commit
						d062cc5420
					
				@ -1,30 +1,33 @@
 | 
			
		||||
import { decoding, encoding, error } from 'lib0'
 | 
			
		||||
import {
 | 
			
		||||
    UpdateEncoderV1, UpdateEncoderV2, UpdateDecoderV1, UpdateDecoderV2, Transaction, Item, StructStore // eslint-disable-line
 | 
			
		||||
    UpdateEncoderV1, UpdateEncoderV2, UpdateDecoderV1, UpdateDecoderV2, Transaction, Item, StructStore, // eslint-disable-line
 | 
			
		||||
    WeakLink,
 | 
			
		||||
    findRootTypeKey,
 | 
			
		||||
    ID,
 | 
			
		||||
    find,
 | 
			
		||||
    ContentType
 | 
			
		||||
  } from '../internals.js'
 | 
			
		||||
  
 | 
			
		||||
  export class ContentLink {
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {Item} item
 | 
			
		||||
     * @param {WeakLink<any>|{parent:string|ID,item:string|ID}} link
 | 
			
		||||
     */
 | 
			
		||||
    constructor (item) {
 | 
			
		||||
      /**
 | 
			
		||||
       * @type {Item}
 | 
			
		||||
       */
 | 
			
		||||
      this.item = item
 | 
			
		||||
    constructor (link) {
 | 
			
		||||
      this.link = link
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
     * @return {number}
 | 
			
		||||
     */
 | 
			
		||||
    getLength () {
 | 
			
		||||
      return this.item.length
 | 
			
		||||
      return 1
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
     * @return {Array<any>}
 | 
			
		||||
     */
 | 
			
		||||
    getContent () {
 | 
			
		||||
      throw new Error('not implemented')
 | 
			
		||||
      return [this.link]
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
@ -38,7 +41,7 @@ import {
 | 
			
		||||
     * @return {ContentLink}
 | 
			
		||||
     */
 | 
			
		||||
    copy () {
 | 
			
		||||
      return new ContentLink(this.item)
 | 
			
		||||
      return new ContentLink(this.link)
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
@ -46,7 +49,7 @@ import {
 | 
			
		||||
     * @return {ContentLink}
 | 
			
		||||
     */
 | 
			
		||||
    splice (offset) {
 | 
			
		||||
      throw new Error('not implemented')
 | 
			
		||||
      throw error.methodUnimplemented()
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
@ -54,19 +57,57 @@ import {
 | 
			
		||||
     * @return {boolean}
 | 
			
		||||
     */
 | 
			
		||||
    mergeWith (right) {
 | 
			
		||||
      throw new Error('not implemented')
 | 
			
		||||
      return false
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {Transaction} transaction
 | 
			
		||||
     * @param {Item} item
 | 
			
		||||
     */
 | 
			
		||||
    integrate (transaction, item) {}
 | 
			
		||||
    integrate (transaction, item) {
 | 
			
		||||
      if (this.link.constructor !== WeakLink) {
 | 
			
		||||
        let { parent, item } = /** @type {any} */ (this.link)
 | 
			
		||||
        let key = null
 | 
			
		||||
        if (parent.constructor === ID) {
 | 
			
		||||
          const parentItem = find(transaction.doc.store, parent)
 | 
			
		||||
          if (parentItem.constructor === Item) {
 | 
			
		||||
            parent = /** @type {ContentType} */ (parentItem.content).type
 | 
			
		||||
          } else {
 | 
			
		||||
            parent = null
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          parent = transaction.doc.share.get(parent)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (item.constructor === ID) {
 | 
			
		||||
          item = find(transaction.doc.store, item)
 | 
			
		||||
        } else {
 | 
			
		||||
          key = item
 | 
			
		||||
          item = parent._map.get(key)
 | 
			
		||||
        }
 | 
			
		||||
        this.link = new WeakLink(parent, item, key)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const link = /** @type {WeakLink<any>} */ (this.link)
 | 
			
		||||
      if (link.item.constructor === Item) {
 | 
			
		||||
        if (link.item.linkedBy === null) {
 | 
			
		||||
            link.item.linkedBy = new Set()
 | 
			
		||||
        }
 | 
			
		||||
        link.item.linkedBy.add(link)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {Transaction} transaction
 | 
			
		||||
     */
 | 
			
		||||
    delete (transaction) {}
 | 
			
		||||
    delete (transaction) {
 | 
			
		||||
      const link = /** @type {WeakLink<any>} */ (this.link)
 | 
			
		||||
      if (link.item.constructor === Item) {
 | 
			
		||||
        if (link.item.linkedBy !== null) {
 | 
			
		||||
          link.item.linkedBy.delete(link)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {StructStore} store
 | 
			
		||||
@ -78,14 +119,34 @@ import {
 | 
			
		||||
     * @param {number} offset
 | 
			
		||||
     */
 | 
			
		||||
    write (encoder, offset) {
 | 
			
		||||
      throw new Error('not implemented')
 | 
			
		||||
      const link = /** @type {WeakLink<any>} */ (this.link)
 | 
			
		||||
      let flags = 0
 | 
			
		||||
      const parentItem = link.source._item
 | 
			
		||||
      if (parentItem) {
 | 
			
		||||
        flags |= 1
 | 
			
		||||
      }
 | 
			
		||||
      if (link.key) {
 | 
			
		||||
        flags |= 2
 | 
			
		||||
      }
 | 
			
		||||
      encoding.writeVarUint(encoder.restEncoder, flags)
 | 
			
		||||
      if (parentItem) {
 | 
			
		||||
        encoder.writeLeftID(parentItem.id)
 | 
			
		||||
      } else {
 | 
			
		||||
        const ykey = findRootTypeKey(link.source)
 | 
			
		||||
        encoder.writeString(ykey)
 | 
			
		||||
      }
 | 
			
		||||
      if (link.key !== null) {
 | 
			
		||||
        encoder.writeString(link.key)
 | 
			
		||||
      } else {
 | 
			
		||||
        encoder.writeLeftID(link.item.id)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    /**
 | 
			
		||||
     * @return {number}
 | 
			
		||||
     */
 | 
			
		||||
    getRef () {
 | 
			
		||||
      return 10
 | 
			
		||||
      return 11
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
@ -94,6 +155,19 @@ import {
 | 
			
		||||
   * @return {ContentLink}
 | 
			
		||||
   */
 | 
			
		||||
  export const readContentWeakLink = decoder => {
 | 
			
		||||
    throw new Error('not implemented')
 | 
			
		||||
    const flags = decoding.readVarUint(decoder.restDecoder)
 | 
			
		||||
    let parent
 | 
			
		||||
    let item
 | 
			
		||||
    if ((flags & 1) !== 0) {
 | 
			
		||||
      parent = decoder.readLeftID()
 | 
			
		||||
    } else {
 | 
			
		||||
      parent = decoder.readString()
 | 
			
		||||
    }
 | 
			
		||||
    if ((flags & 2) !== 0) {
 | 
			
		||||
      item = decoder.readString()
 | 
			
		||||
    } else {
 | 
			
		||||
      item = decoder.readLeftID()
 | 
			
		||||
    }
 | 
			
		||||
    return new ContentLink({parent, item})
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
@ -24,7 +24,9 @@ import {
 | 
			
		||||
  readContentType,
 | 
			
		||||
  addChangedTypeToTransaction,
 | 
			
		||||
  isDeleted,
 | 
			
		||||
  StackItem, DeleteSet, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction // eslint-disable-line
 | 
			
		||||
  StackItem, DeleteSet, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction, // eslint-disable-line
 | 
			
		||||
  WeakLink,
 | 
			
		||||
  ContentLink
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as error from 'lib0/error'
 | 
			
		||||
@ -296,6 +298,13 @@ export class Item extends AbstractStruct {
 | 
			
		||||
     * @type {ID | null}
 | 
			
		||||
     */
 | 
			
		||||
    this.redone = null
 | 
			
		||||
    /**
 | 
			
		||||
     * If this item was referenced by other weak links, here we keep the references
 | 
			
		||||
     * to these weak refs.
 | 
			
		||||
     * 
 | 
			
		||||
     * @type {Set<WeakLink<any>> | null}
 | 
			
		||||
     */
 | 
			
		||||
    this.linkedBy = null
 | 
			
		||||
    /**
 | 
			
		||||
     * @type {AbstractContent}
 | 
			
		||||
     */
 | 
			
		||||
@ -511,6 +520,7 @@ export class Item extends AbstractStruct {
 | 
			
		||||
        /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this)
 | 
			
		||||
        if (this.left !== null) {
 | 
			
		||||
          // this is the current attribute value of parent. delete right
 | 
			
		||||
          this.linkedBy = this.left.linkedBy
 | 
			
		||||
          this.left.delete(transaction)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@ -579,6 +589,8 @@ export class Item extends AbstractStruct {
 | 
			
		||||
      this.deleted === right.deleted &&
 | 
			
		||||
      this.redone === null &&
 | 
			
		||||
      right.redone === null &&
 | 
			
		||||
      this.linkedBy === null &&
 | 
			
		||||
      right.linkedBy === null &&
 | 
			
		||||
      this.content.constructor === right.content.constructor &&
 | 
			
		||||
      this.content.mergeWith(right.content)
 | 
			
		||||
    ) {
 | 
			
		||||
@ -624,6 +636,7 @@ export class Item extends AbstractStruct {
 | 
			
		||||
      addToDeleteSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
 | 
			
		||||
      addChangedTypeToTransaction(transaction, parent, this.parentSub)
 | 
			
		||||
      this.content.delete(transaction)
 | 
			
		||||
      this.linkedBy = null
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -720,8 +733,8 @@ export const contentRefs = [
 | 
			
		||||
  readContentType, // 7
 | 
			
		||||
  readContentAny, // 8
 | 
			
		||||
  readContentDoc, // 9
 | 
			
		||||
  readContentWeakLink, // 10
 | 
			
		||||
  () => { error.unexpectedCase() } // 10 - Skip is not ItemContent
 | 
			
		||||
  () => { error.unexpectedCase() }, // 10 - Skip is not ItemContent
 | 
			
		||||
  readContentWeakLink // 11
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import {
 | 
			
		||||
  ContentAny,
 | 
			
		||||
  ContentBinary,
 | 
			
		||||
  getItemCleanStart,
 | 
			
		||||
  ContentDoc, YText, YArray, UpdateEncoderV1, UpdateEncoderV2, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, // eslint-disable-line
 | 
			
		||||
  ContentDoc, YText, YArray, UpdateEncoderV1, UpdateEncoderV2, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, WeakLink, ContentLink, // eslint-disable-line
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as map from 'lib0/map'
 | 
			
		||||
@ -669,6 +669,10 @@ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem,
 | 
			
		||||
              left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)))
 | 
			
		||||
              left.integrate(transaction, 0)
 | 
			
		||||
              break
 | 
			
		||||
            case WeakLink:
 | 
			
		||||
              left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentLink(/** @type {WeakLink<any>} */ (c)))
 | 
			
		||||
              left.integrate(transaction, 0)
 | 
			
		||||
              break
 | 
			
		||||
            default:
 | 
			
		||||
              if (c instanceof AbstractType) {
 | 
			
		||||
                left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(c))
 | 
			
		||||
@ -851,6 +855,9 @@ export const typeMapSet = (transaction, parent, key, value) => {
 | 
			
		||||
      case Doc:
 | 
			
		||||
        content = new ContentDoc(/** @type {Doc} */ (value))
 | 
			
		||||
        break
 | 
			
		||||
      case WeakLink:
 | 
			
		||||
        content = new ContentLink(/** @type {WeakLink<any>} */ (value))
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (value instanceof AbstractType) {
 | 
			
		||||
          content = new ContentType(value)
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,7 @@
 | 
			
		||||
import { AbstractType, GC, Item, createID } from "yjs"
 | 
			
		||||
import { findMarker, typeMapGet } from "./AbstractType.js"
 | 
			
		||||
import { error } from "lib0"
 | 
			
		||||
import { Transaction, getItemCleanEnd, getItemCleanStart } from "src/internals.js"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @template T
 | 
			
		||||
@ -5,13 +9,82 @@
 | 
			
		||||
 * Weak link to another value stored somewhere in the document.
 | 
			
		||||
 */
 | 
			
		||||
export class WeakLink {
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a reference to an underlying value existing somewhere on in the document.
 | 
			
		||||
     * 
 | 
			
		||||
     * @return {T|undefined}
 | 
			
		||||
     */
 | 
			
		||||
    deref() {
 | 
			
		||||
        throw new Error('not implemented')
 | 
			
		||||
  /**
 | 
			
		||||
    * @param {AbstractType<any>} source
 | 
			
		||||
    * @param {Item|GC} item
 | 
			
		||||
    * @param {string|null} key
 | 
			
		||||
    */
 | 
			
		||||
  constructor(source, item, key) {
 | 
			
		||||
    this.source = source
 | 
			
		||||
    this.item = item
 | 
			
		||||
    this.key = key
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns a reference to an underlying value existing somewhere on in the document.
 | 
			
		||||
   * 
 | 
			
		||||
   * @return {T|undefined}
 | 
			
		||||
   */
 | 
			
		||||
  deref() {
 | 
			
		||||
    if (this.key) {
 | 
			
		||||
      return /** @type {T|undefined} */ (typeMapGet(this.source, this.key))
 | 
			
		||||
    } else {
 | 
			
		||||
      if (this.item.constructor === Item) {
 | 
			
		||||
        return this.item.content.getContent()[0]
 | 
			
		||||
      } else {
 | 
			
		||||
        return undefined
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const lengthExceeded = error.create('Length exceeded!')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns a {WeakLink} to an YArray element at given index.
 | 
			
		||||
 * 
 | 
			
		||||
 * @param {Transaction} transaction
 | 
			
		||||
 * @param {AbstractType<any>} parent
 | 
			
		||||
 * @param {number} index
 | 
			
		||||
 * @return {WeakLink<any>}
 | 
			
		||||
 */
 | 
			
		||||
export const arrayWeakLink = (transaction, parent, index) => {
 | 
			
		||||
  const marker = findMarker(parent, index)
 | 
			
		||||
  let n = parent._start
 | 
			
		||||
  if (marker !== null) {
 | 
			
		||||
    n = marker.p
 | 
			
		||||
    index -= marker.index
 | 
			
		||||
  }
 | 
			
		||||
  for (; n !== null; n = n.right) {
 | 
			
		||||
    if (!n.deleted && n.countable) {
 | 
			
		||||
      if (index < n.length) {
 | 
			
		||||
        if (index > 0) {
 | 
			
		||||
            n = getItemCleanStart(transaction, createID(n.id.clock, n.id.clock + index))
 | 
			
		||||
        }
 | 
			
		||||
        if (n.length > 1) {
 | 
			
		||||
            n = getItemCleanEnd(transaction, transaction.doc.store, createID(n.id.clock, n.id.clock + 1))
 | 
			
		||||
        }
 | 
			
		||||
        return new WeakLink(parent, n, null)
 | 
			
		||||
      }
 | 
			
		||||
      index -= n.length
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  throw lengthExceeded
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns a {WeakLink} to an YMap element at given key.
 | 
			
		||||
 * 
 | 
			
		||||
 * @param {AbstractType<any>} parent
 | 
			
		||||
 * @param {string} key
 | 
			
		||||
 * @return {WeakLink<any>|undefined}
 | 
			
		||||
 */
 | 
			
		||||
export const mapWeakLink = (parent, key) => {
 | 
			
		||||
  const item = parent._map.get(key)
 | 
			
		||||
  if (item !== undefined) {
 | 
			
		||||
    return new WeakLink(parent, item, key)
 | 
			
		||||
  } else {
 | 
			
		||||
    return undefined
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,8 @@ import {
 | 
			
		||||
  callTypeObservers,
 | 
			
		||||
  transact,
 | 
			
		||||
  ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item, // eslint-disable-line
 | 
			
		||||
  WeakLink
 | 
			
		||||
  WeakLink,
 | 
			
		||||
  arrayWeakLink
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
import { typeListSlice } from './AbstractType.js'
 | 
			
		||||
 | 
			
		||||
@ -209,7 +210,13 @@ export class YArray extends AbstractType {
 | 
			
		||||
   * @return {WeakLink<T>}
 | 
			
		||||
   */
 | 
			
		||||
  link(index) {
 | 
			
		||||
      throw new Error('Method not implemented.')
 | 
			
		||||
    if (this.doc !== null) {
 | 
			
		||||
      return transact(this.doc, transaction => {
 | 
			
		||||
        return arrayWeakLink(transaction, this, index)
 | 
			
		||||
      })
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error('todo')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,8 @@ import {
 | 
			
		||||
  callTypeObservers,
 | 
			
		||||
  transact,
 | 
			
		||||
  UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Transaction, Item, // eslint-disable-line
 | 
			
		||||
  WeakLink
 | 
			
		||||
  WeakLink,
 | 
			
		||||
  mapWeakLink
 | 
			
		||||
} from '../internals.js'
 | 
			
		||||
 | 
			
		||||
import * as iterator from 'lib0/iterator'
 | 
			
		||||
@ -241,7 +242,7 @@ export class YMap extends AbstractType {
 | 
			
		||||
   * @return {WeakLink<MapType>|undefined}
 | 
			
		||||
   */
 | 
			
		||||
  link(key) {
 | 
			
		||||
    throw new Error('Method not implemented.')
 | 
			
		||||
    return mapWeakLink(this, key)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,8 @@ if (isBrowser) {
 | 
			
		||||
  log.createVConsole(document.body)
 | 
			
		||||
}
 | 
			
		||||
runTests({
 | 
			
		||||
  doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions, weakLinks
 | 
			
		||||
  //doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates, relativePositions, 
 | 
			
		||||
  weakLinks
 | 
			
		||||
}).then(success => {
 | 
			
		||||
  /* istanbul ignore next */
 | 
			
		||||
  if (isNode) {
 | 
			
		||||
 | 
			
		||||
@ -5,18 +5,35 @@ import { init, compare } from './testHelper.js'
 | 
			
		||||
/**
 | 
			
		||||
 * @param {t.TestCase} tc
 | 
			
		||||
 */
 | 
			
		||||
export const testBasic = tc => {
 | 
			
		||||
export const testBasicMap = tc => {
 | 
			
		||||
  const doc = new Y.Doc()
 | 
			
		||||
  const map = doc.getMap('map')
 | 
			
		||||
  
 | 
			
		||||
  const nested = new Y.Map()
 | 
			
		||||
  nested.set('a1', 'hello')
 | 
			
		||||
  map.set('a', nested)
 | 
			
		||||
  const link = nested.link('a')
 | 
			
		||||
  const link = map.link('a')
 | 
			
		||||
  map.set('b', link)
 | 
			
		||||
 | 
			
		||||
  const nested2 = map.get('b')
 | 
			
		||||
  t.compare(nested2.toJSON(), nested.toJSON())
 | 
			
		||||
  const link2 = /** @type {Y.WeakLink<any>} */ (map.get('b'))
 | 
			
		||||
  const expected = nested.toJSON()
 | 
			
		||||
  const actual = link2.deref().toJSON()
 | 
			
		||||
  t.compare(actual, expected)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {t.TestCase} tc
 | 
			
		||||
 */
 | 
			
		||||
export const testBasicArray = tc => {
 | 
			
		||||
  const doc = new Y.Doc()
 | 
			
		||||
  const array = doc.getArray('array')
 | 
			
		||||
  array.insert(0, [1,2,3])
 | 
			
		||||
  array.insert(3, [array.link(1)])
 | 
			
		||||
 | 
			
		||||
  t.compare(array.get(0), 1)
 | 
			
		||||
  t.compare(array.get(1), 2)
 | 
			
		||||
  t.compare(array.get(2), 3)
 | 
			
		||||
  t.compare(array.get(3).deref(), 2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user