package mem type Mem interface { Allocate(kind CellKind) (Ptr, error) AllocateAt(ptr Ptr, kind CellKind) error Set(ptr Ptr, v CellData) error Get(ptr Ptr) (CellData, error) Is(ptr Ptr, kind CellKind) bool Kind(ptr Ptr) CellKind Retain(ptr Ptr) error Release(ptr Ptr) error RefCount(ptr Ptr) int } type memImpl struct { cells []cell free []Ptr } func New() Mem { cells := make([]cell, 1) // Reserve NullPtr cells[NullPtr].kind = CellKindForbidden return &memImpl{ cells: cells, free: make([]Ptr, 0), } } func (m *memImpl) Allocate(kind CellKind) (Ptr, error) { if kind == CellKindForbidden || kind == CellKindEmpty { return NullPtr, ErrInvalidCellKind{kind} } if len(m.free) > 0 { idx := m.free[len(m.free)-1] m.free = m.free[:len(m.free)-1] if m.cells[idx].kind != CellKindEmpty { // This should never happen. panic("cell marked as free was not empty") } m.cells[idx] = cell{kind: kind, refs: 1} return Ptr(idx), nil } else { if len(m.cells) > 10000 { return NullPtr, ErrMemOverflow } idx := len(m.cells) m.cells = append(m.cells, cell{kind: kind, refs: 1}) return Ptr(idx), nil } } func (m *memImpl) AllocateAt(ptr Ptr, kind CellKind) error { if kind == CellKindForbidden || kind == CellKindEmpty { return ErrInvalidCellKind{kind} } if ptr < Ptr(len(m.cells)) && m.cells[ptr].kind != CellKindEmpty { return ErrInvalidMemAccess{ptr} } if ptr > 10000 { return ErrMemOverflow } if ptr >= Ptr(len(m.cells)) { m.cells = append(m.cells, make([]cell, ptr-Ptr(len(m.cells))+1)...) } m.cells[ptr] = cell{kind: kind, refs: 1} // Remove cell from free list, if it was there. for i, f := range m.free { if f == ptr { m.free = append(m.free[:i], m.free[i+1:]...) break } } return nil } func (m *memImpl) Set(ptr Ptr, v CellData) error { if err := m.validPtr(ptr); err != nil { return err } if m.cells[ptr].kind != v.MatchingCellKind() { return ErrDifferingCellKind{Ptr: ptr, Expected: m.cells[ptr].kind, Got: v.MatchingCellKind()} } m.cells[ptr].data = v return nil } func (m *memImpl) Get(ptr Ptr) (CellData, error) { if err := m.validPtr(ptr); err != nil { return nil, err } return m.cells[ptr].data, nil } func (m *memImpl) Is(ptr Ptr, kind CellKind) bool { if ptr >= Ptr(len(m.cells)) { return kind == CellKindEmpty } return m.cells[ptr].kind == kind } func (m *memImpl) Kind(ptr Ptr) CellKind { if ptr >= Ptr(len(m.cells)) { return CellKindEmpty } return m.cells[ptr].kind } func (m *memImpl) Retain(ptr Ptr) error { if err := m.validPtr(ptr); err != nil { return err } m.cells[ptr].refs++ return nil } func (m *memImpl) Release(ptr Ptr) error { if err := m.validPtr(ptr); err != nil { return err } m.cells[ptr].refs-- if m.cells[ptr].refs == 0 { c := m.cells[ptr].data if c != nil { if err := c.DropCell(m); err != nil { return err } } m.cells[ptr] = cell{} m.free = append(m.free, ptr) } return nil } func (m *memImpl) RefCount(ptr Ptr) int { if err := m.validPtr(ptr); err != nil { return 0 } return m.cells[ptr].refs } func (m *memImpl) validPtr(ptr Ptr) error { if ptr >= Ptr(len(m.cells)) { return ErrInvalidMemAccess{ptr} } kind := m.cells[ptr].kind if kind == CellKindForbidden || kind == CellKindEmpty { return ErrInvalidMemAccess{ptr} } return nil }