diff --git a/hashmap.go b/hashmap.go index 6635f5f..1d238fd 100644 --- a/hashmap.go +++ b/hashmap.go @@ -1,7 +1,6 @@ package immutable import ( - "fmt" "math" "math/rand" "time" @@ -63,19 +62,19 @@ func (h *HashMap) Get(key Key) Value { totalEntries := uint64(b.entryCount) - fmt.Printf("\nlobSize: %d; h.lobMask: 0x%016x\n", h.lobSize, h.lobMask) - fmt.Printf("hashKey: 0x%016x / selectedBucket: %d / mashedHash: 0x%016x\n", hashkey, selectedBucket, maskedHash) + // fmt.Printf("\nlobSize: %d; h.lobMask: 0x%016x\n", h.lobSize, h.lobMask) + // fmt.Printf("hashKey: 0x%016x / selectedBucket: %d / mashedHash: 0x%016x\n", hashkey, selectedBucket, maskedHash) for b != nil { - fmt.Printf(" entryCount: %d\n", b.entryCount) - fmt.Printf(" entries: [\n") - for i := uint64(0); i < uint64(b.entryCount); i++ { - fmt.Printf(" [0x%016x,%s] -> %s\n", b.hobs.Read(i), b.entries[i].key, b.entries[i].value) - } - fmt.Printf(" ]\n") + // fmt.Printf(" entryCount: %d\n", b.entryCount) + // fmt.Printf(" entries: [\n") + // for i := uint64(0); i < uint64(b.entryCount); i++ { + // fmt.Printf(" [0x%016x,%s] -> %s\n", b.hobs.Read(i), b.entries[i].key, b.entries[i].value) + // } + // fmt.Printf(" ]\n") for index := uint64(0); index < totalEntries; index++ { - fmt.Printf("0x%016x <-> 0x%016x :: %s <-> %s\n", b.hobs.Read(index), maskedHash, b.entries[index].key, key) + // fmt.Printf("0x%016x <-> 0x%016x :: %s <-> %s\n", b.hobs.Read(index), maskedHash, b.entries[index].key, key) if b.hobs.Read(index) == maskedHash && b.entries[index].key == key { return b.entries[index].value } @@ -261,7 +260,7 @@ func createHashMap(size int, options *HashMapOptions) *HashMap { lobMask := uint32(^(0xffffffff << lobSize)) buckets := make([]*bucket, initialSize) - fmt.Printf("lobSize: %d; lobMask: 0x%032b\n", lobSize, lobMask) + // fmt.Printf("lobSize: %d; lobMask: 0x%032b\n", lobSize, lobMask) src := rand.NewSource(time.Now().UnixNano()) random := rand.New(src) diff --git a/memory/memory32.go b/memory/memory32.go index 31fe572..3d1efeb 100644 --- a/memory/memory32.go +++ b/memory/memory32.go @@ -1,7 +1,5 @@ package memory -import "fmt" - const fullBlock = ^uint32(0) // Memories32 is all your memories. @@ -12,45 +10,46 @@ type Memories32 struct { // Assign sets a value to the internal memory at the given index func (m *Memories32) Assign(index uint64, value uint64) { - bitsRemaining := uint64(m.bitsPerEntry) - offset := bitsRemaining * index + bitsRemaining := m.bitsPerEntry + offset := bitsRemaining * uint32(index) byteOffset := offset / bitsInLargeBlock bitOffset := offset % bitsInLargeBlock - fmt.Printf("\nAssigning %032b to index %d\n", value, index) - fmt.Printf("byteOffset: %d, bitOffset: %d, bitsRemaining: %d\n", byteOffset, bitOffset, bitsRemaining) + // fmt.Printf("\nAssigning %064b to index %d\n", value, index) writeBitCount := bitsInLargeBlock - bitOffset if writeBitCount > bitsRemaining { writeBitCount = bitsRemaining } - initial := uint64(m.m[byteOffset]) - mask := uint64(fullBlock << writeBitCount) - result := (initial & ^(^mask << bitOffset)) | ((value & ^mask) << bitOffset) - m.m[byteOffset] = uint32(result) + // fmt.Printf("byteOffset: %d, bitOffset: %d, bitsRemaining: %d, writeBitCount: %d\n", byteOffset, bitOffset, bitsRemaining, writeBitCount) + initial := m.m[byteOffset] + mask := ^(fullExtraLargeBlock << writeBitCount) + result := uint32(value&mask)< %032b\n", byteOffset, initial, result) bitsRemaining -= writeBitCount byteOffset++ - if bitsRemaining > 32 { - o := (uint64(m.bitsPerEntry) - bitsRemaining) - result := ((value & (uint64(fullBlock) << o)) >> o) - m.m[byteOffset] = uint32(result) - fmt.Printf("result at %d: %032b\n", byteOffset, m.m[byteOffset]) + if bitsRemaining >= 32 { + o := m.bitsPerEntry - bitsRemaining + result := uint32((value & (fullExtraLargeBlock << o)) >> o) + m.m[byteOffset] = result + // fmt.Printf("result at %d: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -> %032b\n", byteOffset, result) bitsRemaining -= 32 byteOffset++ } if bitsRemaining > 0 { - initial := uint64(m.m[byteOffset]) - mask := uint64(fullBlock << bitsRemaining) - result := (initial & mask) | ((value & (^mask << writeBitCount)) >> writeBitCount) - m.m[byteOffset] = uint32(result) + writeBitCount = m.bitsPerEntry - bitsRemaining + initial := m.m[byteOffset] + mask := fullExtraLargeBlock << bitsRemaining + result := (initial & (fullBlock << bitsRemaining)) | uint32((value&((^mask)<>writeBitCount) + m.m[byteOffset] = result - fmt.Printf("result at %d: %032b\n", byteOffset, m.m[byteOffset]) + // fmt.Printf("result at %d: %032b -> %032b\n", byteOffset, initial, result) } } @@ -60,36 +59,34 @@ func (m *Memories32) Read(index uint64) (result uint64) { offset := bitsRemaining * index bitOffset := offset % bitsInLargeBlock byteOffset := offset / bitsInLargeBlock - fmt.Printf("\nbitOffset: %d, byteOffset: %d\n", bitOffset, byteOffset) - fmt.Printf("m.m: %x\n", m.m) + // fmt.Printf("\nbitOffset: %d, byteOffset: %d\n", bitOffset, byteOffset) + // fmt.Printf("m.m: %x\n", m.m) readBitCount := bitsInLargeBlock - bitOffset if readBitCount > bitsRemaining { readBitCount = bitsRemaining } - initial := uint64(m.m[byteOffset]) - mask := uint64(^(fullBlock << readBitCount)) << bitOffset + initial := m.m[byteOffset] + mask := ^(fullBlock << readBitCount) << bitOffset result = uint64((initial & mask) >> bitOffset) bitsRemaining -= readBitCount + byteOffset++ - if bitsRemaining > 0 { - readBitCount = bitsRemaining - if readBitCount > bitsInLargeBlock { - readBitCount = bitsInLargeBlock - } - fmt.Printf("--> %064b; %d; %d\n", result, bitsRemaining, readBitCount) - initial := uint64(m.m[byteOffset+1]) - result |= ((initial & uint64(^(fullBlock << readBitCount))) << (uint64(m.bitsPerEntry) - bitsRemaining)) - bitsRemaining -= readBitCount + if bitsRemaining >= 32 { + // fmt.Printf("--> %064b; %d; %d\n", result, bitsRemaining, 32) + initial := m.m[byteOffset] + result |= (uint64(initial) << (uint64(m.bitsPerEntry) - bitsRemaining)) + bitsRemaining -= 32 + byteOffset++ } if bitsRemaining > 0 { - initial := uint64(m.m[byteOffset+2]) - fmt.Printf("--> %064b; %d\n", result, bitsRemaining) - result |= ((initial & uint64(^(fullBlock << bitsRemaining))) << (uint64(m.bitsPerEntry) - bitsRemaining)) + initial := m.m[byteOffset] + // fmt.Printf("--> %064b; %d\n", result, bitsRemaining) + result |= uint64(initial&(fullBlock>>(32-bitsRemaining))) << (uint64(m.bitsPerEntry) - bitsRemaining) } - fmt.Printf("--> %064b\n", result) + // fmt.Printf("--> %064b\n", result) return result } diff --git a/memory/memory32_test.go b/memory/memory32_test.go index fc7efd0..481096b 100644 --- a/memory/memory32_test.go +++ b/memory/memory32_test.go @@ -1,6 +1,7 @@ package memory import ( + "fmt" "math" "math/rand" "testing" @@ -55,62 +56,91 @@ func evaluateLargeRead(t *testing.T, bitCount, count uint32, readIndex, expected } func Test_Large_Assign(t *testing.T) { - evaluateLargeAssign(t, 4, 1, 0, 0x000000000000000f, memoryMap32{0: 0x0000000f}, nil) - evaluateLargeAssign(t, 4, 2, 1, 0x000000000000000f, memoryMap32{0: 0x000000f0}, nil) - evaluateLargeAssign(t, 4, 3, 2, 0x000000000000000f, memoryMap32{0: 0x00000f00}, nil) - evaluateLargeAssign(t, 6, 2, 1, 0x000000000000003f, memoryMap32{0: 0x00000fc0}, nil) - evaluateLargeAssign(t, 11, 2, 1, 0x00000000000007ff, memoryMap32{0: 0x003ff800}, nil) - evaluateLargeAssign(t, 24, 2, 1, 0x0000000000ffffff, memoryMap32{0: 0xff000000, 1: 0xffff}, nil) - evaluateLargeAssign(t, 31, 1, 0, 0x000000002aaaaaaa, memoryMap32{0: 0x2aaaaaaa}, nil) - evaluateLargeAssign(t, 31, 1, 0, 0x0000000055555555, memoryMap32{0: 0x55555555}, nil) - evaluateLargeAssign(t, 31, 1, 0, 0x000000007fffffff, memoryMap32{0: 0x7fffffff}, nil) - evaluateLargeAssign(t, 31, 2, 1, 0x000000002aaaaaaa, memoryMap32{1: 0x15555555}, nil) - evaluateLargeAssign(t, 31, 2, 1, 0x0000000055555555, memoryMap32{0: 0x80000000, 1: 0x2aaaaaaa}, nil) - evaluateLargeAssign(t, 31, 2, 1, 0x000000007fffffff, memoryMap32{0: 0x80000000, 1: 0x3fffffff}, nil) - evaluateLargeAssign(t, 32, 1, 0, 0x0000000055555555, memoryMap32{0: 0x55555555}, nil) - evaluateLargeAssign(t, 32, 1, 0, 0x00000000aaaaaaaa, memoryMap32{0: 0xaaaaaaaa}, nil) - evaluateLargeAssign(t, 32, 1, 0, 0x00000000ffffffff, memoryMap32{0: 0xffffffff}, nil) - evaluateLargeAssign(t, 32, 2, 1, 0x0000000055555555, memoryMap32{1: 0x55555555}, nil) - evaluateLargeAssign(t, 32, 2, 1, 0x00000000aaaaaaaa, memoryMap32{1: 0xaaaaaaaa}, nil) - evaluateLargeAssign(t, 32, 2, 1, 0x00000000ffffffff, memoryMap32{1: 0xffffffff}, nil) - evaluateLargeAssign(t, 63, 1, 0, 0x5555555555555555, memoryMap32{0: 0x55555555, 1: 0x55555555}, nil) - evaluateLargeAssign(t, 63, 1, 0, 0x2aaaaaaaaaaaaaaa, memoryMap32{0: 0xaaaaaaaa, 1: 0x2aaaaaaa}, nil) - evaluateLargeAssign(t, 63, 1, 0, 0x7fffffffffffffff, memoryMap32{0: 0xffffffff, 1: 0x7fffffff}, nil) - evaluateLargeAssign(t, 63, 2, 1, 0x5555555555555555, memoryMap32{1: 0x80000000, 2: 0xaaaaaaaa, 3: 0x2aaaaaaa}, nil) - evaluateLargeAssign(t, 63, 2, 1, 0x2aaaaaaaaaaaaaaa, memoryMap32{2: 0x55555555, 3: 0x15555555}, nil) - evaluateLargeAssign(t, 63, 2, 1, 0x7fffffffffffffff, memoryMap32{1: 0x80000000, 2: 0xffffffff, 3: 0x3fffffff}, nil) - evaluateLargeAssign(t, 64, 2, 1, 0x5555555555555555, memoryMap32{2: 0x55555555, 3: 0x55555555}, nil) - evaluateLargeAssign(t, 64, 2, 1, 0xaaaaaaaaaaaaaaaa, memoryMap32{2: 0xaaaaaaaa, 3: 0xaaaaaaaa}, nil) - evaluateLargeAssign(t, 64, 2, 1, 0xffffffffffffffff, memoryMap32{2: 0xffffffff, 3: 0xffffffff}, nil) - o := &assignOptions{true} - evaluateLargeAssign(t, 4, 1, 0, 0x0, memoryMap32{0: 0xfffffff0}, o) - evaluateLargeAssign(t, 4, 2, 1, 0x0, memoryMap32{0: 0xffffff0f}, o) - evaluateLargeAssign(t, 4, 3, 2, 0x0, memoryMap32{0: 0xfffff0ff}, o) - evaluateLargeAssign(t, 6, 2, 1, 0x0, memoryMap32{0: 0xfffff03f}, o) - evaluateLargeAssign(t, 11, 2, 1, 0x0, memoryMap32{0: 0xffc007ff}, o) - evaluateLargeAssign(t, 24, 2, 1, 0x0, memoryMap32{0: 0x00ffffff, 1: 0xffff0000}, o) - evaluateLargeAssign(t, 31, 1, 0, 0x0, memoryMap32{0: 0x80000000}, o) - evaluateLargeAssign(t, 31, 2, 1, 0x0, memoryMap32{0: 0x7fffffff, 1: 0xc0000000}, o) -} -func evaluateLargeAssign(t *testing.T, bitCount, count uint32, writeIndex, value uint64, assessment memoryMap32, options *assignOptions) { - m := AllocateMemories(LargeBlock, bitCount, count) - mem := m.(*Memories32).m - if options != nil && options.initInvert { - for k := range mem { - mem[k] = 0xffffffff - } + testCases := []struct { + bitCount uint32 + count uint32 + writeIndex uint64 + value uint64 + assessment memoryMap32 + options *assignOptions + }{ + {4, 1, 0, 0x000000000000000f, memoryMap32{0: 0x0000000f}, nil}, + {4, 2, 1, 0x000000000000000f, memoryMap32{0: 0x000000f0}, nil}, + {4, 3, 2, 0x000000000000000f, memoryMap32{0: 0x00000f00}, nil}, + {6, 2, 1, 0x000000000000003f, memoryMap32{0: 0x00000fc0}, nil}, + {11, 2, 1, 0x00000000000007ff, memoryMap32{0: 0x003ff800}, nil}, + {24, 2, 1, 0x0000000000ffffff, memoryMap32{0: 0xff000000, 1: 0xffff}, nil}, + {31, 1, 0, 0x000000002aaaaaaa, memoryMap32{0: 0x2aaaaaaa}, nil}, + {31, 1, 0, 0x0000000055555555, memoryMap32{0: 0x55555555}, nil}, + {31, 1, 0, 0x000000007fffffff, memoryMap32{0: 0x7fffffff}, nil}, + {31, 2, 1, 0x000000002aaaaaaa, memoryMap32{1: 0x15555555}, nil}, + {31, 2, 1, 0x0000000055555555, memoryMap32{0: 0x80000000, 1: 0x2aaaaaaa}, nil}, + {31, 2, 1, 0x000000007fffffff, memoryMap32{0: 0x80000000, 1: 0x3fffffff}, nil}, + {32, 1, 0, 0x0000000055555555, memoryMap32{0: 0x55555555}, nil}, + {32, 1, 0, 0x00000000aaaaaaaa, memoryMap32{0: 0xaaaaaaaa}, nil}, + {32, 1, 0, 0x00000000ffffffff, memoryMap32{0: 0xffffffff}, nil}, + {32, 2, 1, 0x0000000055555555, memoryMap32{1: 0x55555555}, nil}, + {32, 2, 1, 0x00000000aaaaaaaa, memoryMap32{1: 0xaaaaaaaa}, nil}, + {32, 2, 1, 0x00000000ffffffff, memoryMap32{1: 0xffffffff}, nil}, + {63, 1, 0, 0x5555555555555555, memoryMap32{0: 0x55555555, 1: 0x55555555}, nil}, + {63, 1, 0, 0x2aaaaaaaaaaaaaaa, memoryMap32{0: 0xaaaaaaaa, 1: 0x2aaaaaaa}, nil}, + {63, 1, 0, 0x7fffffffffffffff, memoryMap32{0: 0xffffffff, 1: 0x7fffffff}, nil}, + {63, 2, 1, 0x5555555555555555, memoryMap32{1: 0x80000000, 2: 0xaaaaaaaa, 3: 0x2aaaaaaa}, nil}, + {63, 2, 1, 0x2aaaaaaaaaaaaaaa, memoryMap32{2: 0x55555555, 3: 0x15555555}, nil}, + {63, 2, 1, 0x7fffffffffffffff, memoryMap32{1: 0x80000000, 2: 0xffffffff, 3: 0x3fffffff}, nil}, + {64, 2, 1, 0x5555555555555555, memoryMap32{2: 0x55555555, 3: 0x55555555}, nil}, + {64, 2, 1, 0xaaaaaaaaaaaaaaaa, memoryMap32{2: 0xaaaaaaaa, 3: 0xaaaaaaaa}, nil}, + {64, 2, 1, 0xffffffffffffffff, memoryMap32{2: 0xffffffff, 3: 0xffffffff}, nil}, + + {4, 1, 0, 0x0, memoryMap32{0: 0xfffffff0}, o}, + {4, 2, 1, 0x0, memoryMap32{0: 0xffffff0f}, o}, + {4, 3, 2, 0x0, memoryMap32{0: 0xfffff0ff}, o}, + {6, 2, 1, 0x0, memoryMap32{0: 0xfffff03f}, o}, + {11, 2, 1, 0x0, memoryMap32{0: 0xffc007ff}, o}, + {24, 2, 1, 0x0, memoryMap32{0: 0x00ffffff, 1: 0xffff0000}, o}, + {31, 1, 0, 0x0, memoryMap32{0: 0x80000000}, o}, + {31, 2, 1, 0x0, memoryMap32{0: 0x7fffffff, 1: 0xc0000000}, o}, } - m.Assign(writeIndex, value) - for k, v := range assessment { - result := uint32(mem[k]) - if v != result { - t.Fatalf("At %d, incorrect result from write; expected 0x%016x, got 0x%016x\n", k, v, result) - } + + for index, tc := range testCases { + t.Run(fmt.Sprintf("%d", index), func(t *testing.T) { + m := AllocateMemories(LargeBlock, tc.bitCount, tc.count) + mem := m.(*Memories32).m + if tc.options != nil && tc.options.initInvert { + for k := range mem { + mem[k] = 0xffffffff + } + } + m.Assign(tc.writeIndex, tc.value) + for k, v := range tc.assessment { + result := uint32(mem[k]) + if v != result { + t.Fatalf("At %d, incorrect result from write; expected 0x%08x, got 0x%08x\n", k, v, result) + } + } + }) } } +// func evaluateLargeAssign(t *testing.T, bitCount, count uint32, writeIndex, value uint64, assessment memoryMap32, options *assignOptions) { +// m := AllocateMemories(LargeBlock, bitCount, count) +// mem := m.(*Memories32).m +// if options != nil && options.initInvert { +// for k := range mem { +// mem[k] = 0xffffffff +// } +// } +// m.Assign(writeIndex, value) +// for k, v := range assessment { +// result := uint32(mem[k]) +// if v != result { +// t.Fatalf("At %d, incorrect result from write; expected 0x%016x, got 0x%016x\n", k, v, result) +// } +// } +// } + func Test_Large_Random(t *testing.T) { src := rand.NewSource(time.Now().UnixNano()) random := rand.New(src) @@ -118,13 +148,13 @@ func Test_Large_Random(t *testing.T) { width := uint32(64 - 11) max := int64(math.Pow(2.0, float64(width))) - count := uint64(8) + count := 8 contents := make([]uint64, count) - for i := uint64(0); i < count; i++ { + for i := 0; i < count; i++ { contents[i] = uint64(random.Int63n(max)) } - m := AllocateMemories(LargeBlock, width, 8) + m := AllocateMemories(LargeBlock, width, uint32(count)) for k, v := range contents { m.Assign(uint64(k), v) } @@ -136,46 +166,3 @@ func Test_Large_Random(t *testing.T) { } } } - -// func Test_WriteAndRead2(t *testing.T) { -// count := 4 -// set := make([]uint64, count) -// for i := 0; i < count; i++ { -// set[i] = 0x55555555 -// } -// -// m := AllocateMemories(LargeBlock, 31, 4) -// -// for k, v := range set { -// m.Assign(uint64(k), v) -// } -// -// for k, v := range set { -// result := m.Read(uint64(k)) -// if result != v { -// t.Fatalf("At %d\nexpected %032b\nreceived %032b\n", k, v, result) -// } -// } -// } -// -// func Test_WriteAndRead(t *testing.T) { -// count := 4 -// r := rand.New(rand.NewSource(time.Now().UnixNano())) -// set := make([]uint64, count) -// for i := 0; i < count; i++ { -// set[i] = uint64(r.Int31()) & 0x7fffffff -// } -// -// m := AllocateMemories(LargeBlock, 31, 4) -// -// for k, v := range set { -// m.Assign(uint64(k), v) -// } -// -// for k, v := range set { -// result := m.Read(uint64(k)) -// if result != v { -// t.Fatalf("At %d\nexpected %032b\nreceived %032b\n", k, v, result) -// } -// } -// } diff --git a/memory/memory64_test.go b/memory/memory64_test.go index 5c5f234..d341ed9 100644 --- a/memory/memory64_test.go +++ b/memory/memory64_test.go @@ -1,6 +1,11 @@ package memory -import "testing" +import ( + "math" + "math/rand" + "testing" + "time" +) func Test_ExtraLarge_Read(t *testing.T) { evaluateExtraLargeRead(t, 4, 1, 0, 0xf, memoryMap64{0: 0xf}, nil) @@ -75,3 +80,29 @@ func evaluateExtraLargeAssign(t *testing.T, bitCount, count uint32, writeIndex, } } } + +func Test_ExtraLarge_Random(t *testing.T) { + src := rand.NewSource(time.Now().UnixNano()) + random := rand.New(src) + + width := uint32(64 - 11) + max := int64(math.Pow(2.0, float64(width))) + + count := uint64(8) + contents := make([]uint64, count) + for i := uint64(0); i < count; i++ { + contents[i] = uint64(random.Int63n(max)) + } + + m := AllocateMemories(ExtraLargeBlock, width, 8) + for k, v := range contents { + m.Assign(uint64(k), v) + } + + for k, v := range contents { + result := m.Read(uint64(k)) + if result != v { + t.Fatalf("At %d\nexpected %064b\nreceived %064b\n", k, v, result) + } + } +}