about summary refs log tree commit diff
path: root/pkg/lang/vm/mem/mem.go
blob: 99412eae795b0a2c0df52c1eef5098c281139f54 (plain)
1
2
3
4
5
6
7
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #0000ff }
.highlight .c { color: #0F0 } /* Comment */
.highlight .err { color: #DDD } /* Error */
.highlight .esc { color: #DDD } /* Escape */
.highlight .g { color: #DDD } /* Generic */
.highlight .k { color: #F00 } /* Keyword */
.highlight .l { color: #DDD } /* Literal */
.highlight .n { color: #DDD } /* Name */
.highlight .o { color: #DDD } /* Operator */
.highlight .x { color: #DDD } /* Other */
.highlight .p { color: #DDD } /* Punctuation */
.highlight .ch { color: #0F0 } /* Comment.Hashbang */
.highlight .cm { color: #0F0 } /* Comment.Multiline */
.highlight .cp { color: #E5E5E5 } /* Comment.Preproc */
.highlight .cpf { color: #0F0 } /* Comment.PreprocFile */
.highlight .c1 { color: #0F0 } /* Comment.Single */
.highlight .cs { color: #0F0 } /* Comment.Special */
.highlight .gd { color: #DDD } /* Generic.Deleted */
.highlight .ge { color: #DDD } /* Generic.Emph */
.highlight .ges { color: #DDD } /* Generic.EmphStrong */
.highlight .gr { color: #DDD } /* Generic.Error */
.highlight .gh { color: #DDD } /* Generic.Heading */
.highlight .gi { color: #DDD } /* Generic.Inserted */
.highlight .go { color: #DDD } /* Generic.Output */
.highlight .gp { color: #DDD } /* Generic.Prompt */
.highlight .gs { color: #DDD } /* Generic.Strong */
.highlight .gu { color: #DDD } /* Generic.Subheading */
.highlight .gt { color: #DDD } /* Generic.Traceback */
.highlight .kc { color: #F00 } /* Keyword.Constant */
.highlight .kd { color: #F00 } /* Keyword.Declaration */
.highlight .kn { color: #F00 } /* Keyword.Namespace */
.highlight .kp { color: #F00 } /* Keyword.Pseudo */
.highlight .kr { color: #F00 } /* Keyword.Reserved */
.highlight .kt { color: #EE82EE } /* Keyword.Type */
.highlight .ld { color: #DDD } /* Literal.Date */
.highlight .m { color: #F0F } /* Literal.Number */
.highlight .s { color: #87CEEB } /* Literal.String */
.highlight .na { color: #DDD } /* Name.Attribute */
.highlight .nb { color: #DDD } /* Name.Builtin */
.highlight .nc { color: #DDD } /* Name.Class */
.highlight .no { color: #7FFFD4 } /* Name.Constant */
.highlight .nd { color: #DDD } /* Name.Decorator */
.highlight .ni { color: #DDD } /* Name.Entity */
.highlight .ne { color: #DDD } /* Name.Exception */
.highlight .nf { color: #FF0 } /* Name.Function */
.highlight .nl { color: #DDD } /* Name.Label */
.highlight .nn { color: #DDD } /* Name.Namespace */
.highlight .nx { color: #DDD } /* Name.Other */
.highlight .py { color: #DDD } /* Name.Property */
.highlight .nt { color: #DDD } /* Name.Tag */
.highlight .nv { color: #EEDD82 } /* Name.Variable */
.highlight .ow { color: #F00 } /* Operator.Word */
.highlight .pm { color: #DDD } /* Punctuation.Marker */
.highlight .w { color: #DDD } /* Text.Whitespace */
.highlight .mb { color: #F0F } /* Literal.Number.Bin */
.highlight .mf { color: #F0F } /* Literal.Number.Float */
.highlight .mh { color: #F0F } /* Literal.Number.Hex */
.highlight .mi { color: #F0F } /* Literal.Number.Integer */
.highlight .mo { color: #F0F } /* Literal.Number.Oct */
.highlight .sa { color: #87CEEB } /* Literal.String.Affix */
.highlight .sb { color: #87CEEB } /* Literal.String.Backtick */
.highlight .sc { color: #87CEEB } /* Literal.String.Char */
.highlight .dl { color: #87CEEB } /* Literal.String.Delimiter */
.highlight .sd { color: #87CEEB } /* Literal.String.Doc */
.highlight .s2 { color: #87CEEB } /* Literal.String.Double */
.highlight .se { color: #87CEEB } /* Literal.String.Escape */
.highlight .sh { color: #87CEEB } /* Literal.String.Heredoc */
.highlight .si { color: #87CEEB } /* Literal.String.Interpol */
.highlight .sx { color: #87CEEB } /* Literal.String.Other */
.highlight .sr { color: #87CEEB } /* Literal.String.Regex */
.highlight .s1 { color: #87CEEB } /* Literal.String.Single */
.highlight .ss { color: #87CEEB } /* Literal.String.Symbol */
.highlight .bp { color: #DDD } /* Name.Builtin.Pseudo */
.highlight .fm { color: #FF0 } /* Name.Function.Magic */
.highlight .vc { color: #EEDD82 } /* Name.Variable.Class */
.highlight .vg { color: #EEDD82 } /* Name.Variable.Global */
.highlight .vi { color: #EEDD82 } /* Name.Variable.Instance */
.highlight .vm { color: #EEDD82 } /* Name.Variable.Magic */
.highlight .il { color: #F0F } /* Literal.Number.Integer.Long */
export enum DataType {
    TEXT,
    FILES,
}
176
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 {
			c.DropCell(m)
		}

		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
}