From 2144223879ee68aa787d5eac510d1a96bf8429ac Mon Sep 17 00:00:00 2001 From: Morgan Bazalgette Date: Thu, 16 Nov 2023 16:36:54 +0100 Subject: [PATCH] feat(examples): add p/demo/squid --- examples/gno.land/p/demo/squid/README.md | 36 ++++++++++++ examples/gno.land/p/demo/squid/gno.mod | 1 + examples/gno.land/p/demo/squid/squid.gno | 57 +++++++++++++++++++ examples/gno.land/p/demo/squid/squid_test.gno | 43 ++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 examples/gno.land/p/demo/squid/README.md create mode 100644 examples/gno.land/p/demo/squid/gno.mod create mode 100644 examples/gno.land/p/demo/squid/squid.gno create mode 100644 examples/gno.land/p/demo/squid/squid_test.gno diff --git a/examples/gno.land/p/demo/squid/README.md b/examples/gno.land/p/demo/squid/README.md new file mode 100644 index 00000000000..7fac2e5f8e8 --- /dev/null +++ b/examples/gno.land/p/demo/squid/README.md @@ -0,0 +1,36 @@ +# squid + +``` +package squid // import "gno.land/p/demo/squid" + +Package squid provides a simple way to have sequential IDs which will be ordered +correctly when inserted in an AVL tree. + +Sample usage: + + var id squid.ID + var users avl.Tree + + func NewUser() { + users.Set(id.Next().Binary(), &User{ ... }) + } + +TYPES + +type ID uint64 + An ID is a simple sequential ID generator. + +func FromBinary(b string) (ID, bool) + FromBinary creates a new ID from the given string. + +func (i ID) Binary() string + Binary returns a big-endian binary representation of the ID, suitable to be + used as an AVL key. + +func (i *ID) Next() ID + Next advances the ID i. It will panic if increasing ID would overflow. + +func (i *ID) TryNext() (ID, bool) + TryNext increases i by 1 and returns its value. It returns true if + successful, or false if the increment would result in an overflow. +``` diff --git a/examples/gno.land/p/demo/squid/gno.mod b/examples/gno.land/p/demo/squid/gno.mod new file mode 100644 index 00000000000..3c553138ca6 --- /dev/null +++ b/examples/gno.land/p/demo/squid/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/squid diff --git a/examples/gno.land/p/demo/squid/squid.gno b/examples/gno.land/p/demo/squid/squid.gno new file mode 100644 index 00000000000..73eb4ecbeb2 --- /dev/null +++ b/examples/gno.land/p/demo/squid/squid.gno @@ -0,0 +1,57 @@ +// Package squid provides a simple way to have sequential IDs which will be +// ordered correctly when inserted in an AVL tree. +// +// Sample usage: +// +// var id squid.ID +// var users avl.Tree +// +// func NewUser() { +// users.Set(id.Next().Binary(), &User{ ... }) +// } +package squid + +import "encoding/binary" + +// An ID is a simple sequential ID generator. +type ID uint64 + +// Next advances the ID i. +// It will panic if increasing ID would overflow. +func (i *ID) Next() ID { + next, ok := i.TryNext() + if !ok { + panic("squid: next ID overflows uint64") + } + return next +} + +const maxUint64 uint64 = 1<<64 - 1 + +// TryNext increases i by 1 and returns its value. +// It returns true if successful, or false if the increment would result in +// an overflow. +func (i *ID) TryNext() (ID, bool) { + if *i == maxUint64 { + // Addition will overflow. + return 0, false + } + *i++ + return *i, true +} + +// Binary returns a big-endian binary representation of the ID, +// suitable to be used as an AVL key. +func (i ID) Binary() string { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(i)) + return string(buf) +} + +// FromBinary creates a new ID from the given string. +func FromBinary(b string) (ID, bool) { + if len(b) != 8 { + return 0, false + } + return ID(binary.BigEndian.Uint64([]byte(b))), true +} diff --git a/examples/gno.land/p/demo/squid/squid_test.gno b/examples/gno.land/p/demo/squid/squid_test.gno new file mode 100644 index 00000000000..167e1fee135 --- /dev/null +++ b/examples/gno.land/p/demo/squid/squid_test.gno @@ -0,0 +1,43 @@ +package squid + +import ( + "strings" + "testing" + "fmt" +) + +func TestID(t *testing.T) { + var i ID + + for j := 0; j < 100; j++ { + i.Next() + } + if i != 100 { + t.Fatalf("invalid: wanted %d got %d", 100, i) + } +} + +func TestID_Overflow(t *testing.T) { + i := ID(maxUint64) + + defer func() { + err := recover() + if !strings.Contains(fmt.Sprint(err), "next ID overflows") { + t.Errorf("did not overflow") + } + }() + + i.Next() +} + +func TestID_Binary(t *testing.T) { + var i ID + prev := i.Binary() + + for j := 0; j < 1000; j++ { + cur := i.Next().Binary() + if cur <= prev { + t.Fatalf("cur %x <= prev %x", cur, prev) + } + } +}