Skip to content

Instantly share code, notes, and snippets.

@Gsantomaggio
Last active October 31, 2022 08:27
Show Gist options
  • Save Gsantomaggio/921d2de9d1c751f6b3b4bfecca4e6a9d to your computer and use it in GitHub Desktop.
Save Gsantomaggio/921d2de9d1c751f6b3b4bfecca4e6a9d to your computer and use it in GitHub Desktop.
import json
import time
from json import JSONEncoder
class Foo:
def __init__(self, string_1, string_2, int_1):
self.string_1 = string_1
self.string_1 = string_2
self.int_1 = int_1
class FooWithNested:
def __init__(self, int64_2, int64_1, foo_nested_):
self.int64_2 = int64_2
self.int64_1 = int64_1
self.foo_nested = foo_nested_
# subclass JSONEncoder
class FooEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
start_time = time.time()
x = 1_000_000
for n in range(x):
foo = Foo("String_1", "string_2", 123)
foo_nested = FooWithNested(n + 100, n, foo)
json_string = FooEncoder().encode(foo_nested)
obj = json.loads(json_string, cls=json.JSONDecoder)
txt2 = "Seconds: {0}, iterations: {1}".format((time.time() - start_time), x)
print(txt2)
@Gsantomaggio
Copy link
Author

package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"time"
)

type Foo struct {
	string1 string
	string2 string
	int1    int
}

func (p *Foo) Write(writer *bufio.Writer) (int, error) {
	return WriteMany(writer, p.string1, p.string2, p.int1)
}

func (p *Foo) SizeNeed() int {
	return 4 + len(p.string1) + 4 + len(p.string2) + 4
}

type FooWithNested struct {
	foo    *Foo
	int641 int64
	int642 int64
}

func (p *FooWithNested) SizeNeed() int {
	return p.foo.SizeNeed() + 8 + 8
}

func (p *FooWithNested) Write(writer *bufio.Writer) (int, error) {

	writeFN, err := WriteMany(writer, p.int641, p.int642)
	if err != nil {
		return 0, err
	}
	writeF, err := p.foo.Write(writer)

	if err != nil {
		return 0, err
	}

	return writeF + writeFN, nil
}

func main() {
	const interactions int = 1_000_000
	println("Starting ... ")

	t1 := time.Now()

	for i := 0; i < interactions; i++ {
		foo := &Foo{
			string1: "string_1",
			string2: "String_2",
			int1:    1,
		}

		fooWithNestedFrom := &FooWithNested{
			foo:    foo,
			int641: int64(i) * 2,
			int642: int64(i) + 100,
		}

		buff := new(bytes.Buffer)
		wr := bufio.NewWriterSize(buff, fooWithNestedFrom.SizeNeed())
		_, err := fooWithNestedFrom.Write(wr)
		if err != nil {
			panic(err)
		}

		err = wr.Flush()
		if err != nil {
			panic(err)
		}

		// Read
		readerStream := bufio.NewReader(buff)
		fooWithNestedTo := &FooWithNested{
			foo: &Foo{},
		}
		err = readMany(readerStream, &fooWithNestedTo.int641, &fooWithNestedTo.int642, &fooWithNestedTo.foo.string1, &fooWithNestedTo.foo.string2, &fooWithNestedTo.foo.int1)
		if err != nil {
			panic(err)
		}

		if fooWithNestedTo.foo.string1 != fooWithNestedFrom.foo.string1 {
			panic("string1")
		}

		if fooWithNestedTo.int642 != fooWithNestedFrom.int642 {
			panic("int642")
		}

	}

	t2 := time.Now()

	diff := t2.Sub(t1)
	println("Time taken: ", time.Time{}.Add(diff).Format("15:04:05.000000000"))

}

/////////////////

func readUShort(readerStream *bufio.Reader) (uint16, error) {
	var res uint16
	err := binary.Read(readerStream, binary.BigEndian, &res)
	return res, err
}

func readUInt(readerStream *bufio.Reader) (uint32, error) {
	var res uint32
	err := binary.Read(readerStream, binary.BigEndian, &res)
	return res, err
}

func peekByte(readerStream *bufio.Reader) (uint8, error) {
	res, err := readerStream.Peek(1)
	if err != nil {
		return 0, err
	}
	return res[0], nil
}

func readString(readerStream *bufio.Reader) string {
	// FIXME: handle the potential error from readUShort
	lenString, _ := readUShort(readerStream)
	buff := make([]byte, lenString)
	_ = binary.Read(readerStream, binary.BigEndian, &buff)
	return string(buff)
}

func readByteSlice(readerStream *bufio.Reader) (data []byte, err error) {
	numEntries, err := readUShort(readerStream)
	if err != nil {
		return nil, err
	}
	data = make([]byte, numEntries)
	err = binary.Read(readerStream, binary.BigEndian, data)
	if err != nil {
		return nil, err
	}
	return
}

func readMany(readerStream *bufio.Reader, args ...interface{}) error {
	for _, arg := range args {
		err := readAny(readerStream, arg)
		if err != nil {
			return err
		}
	}
	return nil
}

func readAny(readerStream *bufio.Reader, arg interface{}) error {

	switch arg.(type) {
	case *int:
		uInt, err := readUInt(readerStream)
		if err != nil {
			return err
		}
		*arg.(*int) = int(uInt)
		break
	case *string:
		*arg.(*string) = readString(readerStream)
		break
	case *[]byte:
		byteSlice, err := readByteSlice(readerStream)
		if err != nil {
			return err
		}
		*arg.(*[]byte) = byteSlice
	default:
		err := binary.Read(readerStream, binary.BigEndian, arg)
		if err != nil {
			return err
		}

	}
	return nil
}

func WriteMany(writer *bufio.Writer, args ...interface{}) (int, error) {
	var written int

	for _, arg := range args {
		switch arg.(type) {
		case int:
			err := binary.Write(writer, binary.BigEndian, int32(arg.(int)))
			if err != nil {
				return written, err
			}
			written += binary.Size(int32(arg.(int)))
			break
		case string:
			n, err := writeString(writer, arg.(string))
			if err != nil {
				return written, err
			}
			written += n
			break
		case map[string]string:
			for key, value := range arg.(map[string]string) {
				n, err := writeString(writer, key)
				written += n
				n, err = writeString(writer, value)
				written += n
				if err != nil {
					return written, err
				}
			}
		default:
			err := binary.Write(writer, binary.BigEndian, arg)
			if err != nil {
				return written, err
			}
			written += binary.Size(arg)
		}

	}
	return written, nil
}

func writeString(writer *bufio.Writer, value string) (nn int, err error) {
	shortLen, err := WriteMany(writer, uint16(len(value)))
	if err != nil {
		return 0, err
	}
	byteLen, err := writer.Write([]byte(value))
	return byteLen + shortLen, err
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment