├── README.md ├── binary_routines ├── binary.go ├── binary_test.go └── doc.go ├── functions ├── doc.go ├── functions.go └── functions_test.go ├── pointers └── pointers.go ├── prime_numbers_1 ├── doc.go ├── prime.go └── prime_test.go └── prime_numbers_sieve ├── doc.go ├── prime_sieve.go └── prime_sieve_test.go /README.md: -------------------------------------------------------------------------------- 1 | # Golang-Training-Examples 2 | This repo contains example code used for golang training 3 | 4 | prime_numbers_1 is the first project set after the first training session 5 | prime_numbers_sieve is a Sieve of Eratosthenes implementation for finding primes -------------------------------------------------------------------------------- /binary_routines/binary.go: -------------------------------------------------------------------------------- 1 | // Various binary level routines for demonstration purposes 2 | // Andrew Alston 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "strings" 9 | ) 10 | 11 | // BitwiseAnd performs a bitwise AND between num1 and num2 and prints the results. 12 | // A bitwise AND states that if two bits are set, the resultant bit will be set, 13 | // otherwise the resultant bit will be unset. We use unsigned 16 bit integers here 14 | // purely to make printing and reading easier 15 | func BitwiseAnd(num1, num2 uint16) uint16 { 16 | fmt.Printf("Performing Bitwise AND between %d and %d\n", num1, num2) 17 | fmt.Printf("Binary [%2d]: %016b\n", num1, num1) 18 | fmt.Printf("Binary [%2d]: %016b\n", num2, num2) 19 | fmt.Printf("Result [%2d]: %016b\n", num1&num2, num1&num2) 20 | return num1 & num2 21 | } 22 | 23 | // ExclusiveOr performs a XOR (Exclusive Or) between two numbers and prints the results. 24 | // When an exclusive OR is performed, the result will be 0 if both bits are 25 | // the same (0 ^ 0 = 0, 1 ^ 1 = 0) or 1 if they weren't (0^1 = 1) 26 | func ExclusiveOr(num1, num2 uint16) uint16 { 27 | fmt.Printf("Performing Exclusive OR between %d and %d\n", num1, num2) 28 | fmt.Printf("Binary [%2d]: %016b\n", num1, num1) 29 | fmt.Printf("Binary [%2d]: %016b\n", num2, num2) 30 | fmt.Printf("Result [%2d]: %016b\n", num1^num2, num1^num2) 31 | return num1 ^ num2 32 | } 33 | 34 | // BitwiseOr performs a bitwise OR between two numbers and prints the results. 35 | // When a bitwise OR is performed, the result will be 1 if either of the bits 36 | // were 1, otherwise the result will be 0 37 | func BitwiseOr(num1, num2 uint16) uint16 { 38 | fmt.Printf("Performing Logical OR between %d and %d\n", num1, num2) 39 | fmt.Printf("Binary [%2d]: %016b\n", num1, num1) 40 | fmt.Printf("Binary [%2d]: %016b\n", num2, num2) 41 | fmt.Printf("Result [%2d]: %016b\n", num1|num2, num1|num2) 42 | return num1 | num2 43 | } 44 | 45 | // LeftShift shifts num1 left by the number of places specified in num2 46 | // A Left Shift shifts all bits to the left by pushing zeros in from the right 47 | // and dropping the left most bits. This effectively doubles the num in question 48 | // for each bit shifted left 49 | func LeftShift(num1, num2 uint16) uint16 { 50 | fmt.Printf("Left shifting %d by %d bits\n", num1, num2) 51 | fmt.Printf("Binary [%3d]: %016b\n", num1, num1) 52 | fmt.Printf("Result [%3d]: %016b\n", num1<>num2, num1>>num2) 63 | return num1 >> num2 64 | } 65 | 66 | // TestBit sets to see if a binary bit is set in the given number. It assumes 67 | // that numbers are numbered from the right starting at 0 and returns true 68 | // if the bit is set or false if the bit is unset. This works by shifting the 69 | // given number to the right by x places, setting all but the right most to zero 70 | // and then verifying that the result is 1. For this, to cater for different 71 | // size integers we use an interface type and do some assertion 72 | func TestBit(num1 interface{}, bit uint8) (bool, error) { 73 | switch num1.(type) { 74 | case uint8: 75 | fmt.Printf("Binary [%3d] [%08b] >> %d [bit %d] == [%3d] %08b [%v]\n", 76 | num1, num1, bit, 7-bit, num1.(uint8)>>(7-bit), num1.(uint8)>>(7-bit), (num1.(uint8)>>(7-bit))&1 == 1) 77 | return (num1.(uint8)>>(7-bit))&1 == 1, nil 78 | case uint16: 79 | fmt.Printf("Binary [%3d] [%08b] >> %d [bit %d]== [%3d] %08b [%v]\n", 80 | num1, num1, bit, 15-bit, num1.(uint16)>>(15-bit), num1.(uint16)>>(15-bit), (num1.(uint16)>>(15-bit))&1 == 1) 81 | return (num1.(uint16)>>uint16(15-bit))&1 == 1, nil 82 | case uint32: 83 | fmt.Printf("Binary [%3d] [%08b] >> %d [bit %d] == [%3d] %08b [%v]\n", 84 | num1, num1, bit, 31-bit, num1.(uint32)>>(31-bit), num1.(uint32)>>(31-bit), (num1.(uint32)>>(31-bit))&1 == 1) 85 | return (num1.(uint32)>>uint32(31-bit))&1 == 1, nil 86 | case uint64: 87 | fmt.Printf("Binary [%3d] [%08b] >> %d [bit %d] == [%3d] %08b [%v]\n", 88 | num1, num1, bit, 63-bit, num1.(uint64)>>(63-bit), num1.(uint64)>>(63-bit), (num1.(uint64)>>(63-bit))&1 == 1) 89 | return (num1.(uint64)>>uint64(61-bit))&1 == 1, nil 90 | default: 91 | return false, fmt.Errorf("error, unrecognized type") 92 | } 93 | } 94 | 95 | // Variadic OR takes a variadic argument of a number of integers, performs a logical OR against all 96 | // of those integers and returns the result 97 | func VariadicOr(input ...int) int { 98 | var res int 99 | // strSlice exists just so we can make a nice output string 100 | var strSlice = make([]string, len(input)) 101 | for i, in := range input { 102 | // We put our input integers into our string slice so we can print them nicely with a join 103 | strSlice[i] = fmt.Sprintf("%d", in) 104 | res = res | in 105 | } 106 | fmt.Printf("Performing %s = %d\n", strings.Join(strSlice, "|"), res) 107 | return res 108 | } 109 | 110 | // CombinedContains tests if a number is logically part of another number at a binary level. As an example: 111 | // Given numbers 1, 2, 4, 8, if a logical OR is performed, they will produce a single number with the 112 | // left 4 most bits set. If we then do a logical AND of any of those against the result, we will have a 113 | // non-zero return. 114 | func CombinedContains(num1, num2 int) bool { 115 | fmt.Printf("Input [%d] [%08b] & [%d] [%08b] == [%d] [%08b] [%v]\n", 116 | num1, num1, num2, num2, num1&num2, num1&num2, !(num1&num2 == 0)) 117 | return !(num1&num2 == 0) 118 | } 119 | 120 | // TestByStaticMask tests a uint8 by performing an AND against a constant. 121 | // In this particular case we generate the constants using iota, which effectively 122 | // acts as an incrementer for a shift in the constant declarations 123 | func TestByStaticMask(num1, bit uint8) bool { 124 | // We set bit7 constant as zero and then set the subsequent constants 125 | // by 1 shifted left by an incrementing amounts (1 - 7) 126 | const ( 127 | bit7 uint8 = 1 128 | bit6 uint8 = 1 << iota 129 | bit5 130 | bit4 131 | bit3 132 | bit2 133 | bit1 134 | bit0 135 | ) 136 | 137 | switch bit { 138 | case 0: 139 | return num1&bit0 == bit0 140 | case 1: 141 | return num1&bit1 == bit1 142 | case 2: 143 | return num1&bit2 == bit2 144 | case 3: 145 | return num1&bit3 == bit3 146 | case 4: 147 | return num1&bit4 == bit4 148 | case 5: 149 | return num1&bit5 == bit5 150 | case 6: 151 | return num1&bit6 == bit6 152 | case 7: 153 | return num1&bit7 == bit7 154 | default: 155 | return false 156 | } 157 | } 158 | 159 | func main() { 160 | fmt.Printf("Logical AND:\n") 161 | BitwiseAnd(50, 60) 162 | fmt.Printf("\nExclusive OR:\n") 163 | ExclusiveOr(50, 60) 164 | fmt.Printf("\nLogical OR:\n") 165 | BitwiseOr(50, 60) 166 | fmt.Printf("\nLeft Shift:\n") 167 | LeftShift(50, 4) 168 | fmt.Printf("\nRight Shift:\n") 169 | RightShift(50, 2) 170 | fmt.Printf("\nBit Testing:\n") 171 | _, _ = TestBit(uint8(50), 7) 172 | _, _ = TestBit(uint8(50), 6) 173 | _, _ = TestBit(uint8(50), 5) 174 | _, _ = TestBit(uint8(50), 4) 175 | fmt.Printf("\nVaradic OR:\n") 176 | res := VariadicOr(1, 2, 4, 8, 16, 32) 177 | fmt.Printf("%d\n", res) 178 | fmt.Printf("\nCombinedContains [Match]:\n") 179 | CombinedContains(res, 4) 180 | fmt.Printf("\nCombinedContains [No Match]:\n") 181 | CombinedContains(res, 64) 182 | fmt.Printf("\nStatic Bitmask testing\n") 183 | x := uint8(193) 184 | for i := uint8(0); i <= 7; i++ { 185 | fmt.Printf("Testing for bit %d in number [%3d] [%08b]: [%v]\n", i, x, x, TestByStaticMask(x, i)) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /binary_routines/binary_test.go: -------------------------------------------------------------------------------- 1 | // Binary level functions test routines 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestBitwiseAnd(t *testing.T) { 10 | tp := struct { 11 | a, b uint16 12 | want uint16 13 | }{5, 6, 4} 14 | t.Run(fmt.Sprintf("%d,%d", tp.a, tp.b), func(*testing.T) { 15 | ans := BitwiseAnd(tp.a, tp.b) 16 | if ans != tp.want { 17 | t.Errorf("%d [%016b] != %d [%016b]", ans, ans, tp.want, tp.want) 18 | } 19 | }) 20 | } 21 | 22 | func TestBitwiseOr(t *testing.T) { 23 | tp := struct { 24 | a, b uint16 25 | want uint16 26 | }{5, 6, 7} 27 | t.Run(fmt.Sprintf("%d,%d", tp.a, tp.b), func(*testing.T) { 28 | ans := BitwiseOr(tp.a, tp.b) 29 | if ans != tp.want { 30 | t.Errorf("%d [%016b] != %d [%016b]", ans, ans, tp.want, tp.want) 31 | } 32 | }) 33 | } 34 | 35 | func TestExclusiveOr(t *testing.T) { 36 | tp := struct { 37 | a, b uint16 38 | want uint16 39 | }{5, 6, 3} 40 | t.Run(fmt.Sprintf("%d,%d", tp.a, tp.b), func(*testing.T) { 41 | ans := ExclusiveOr(tp.a, tp.b) 42 | if ans != tp.want { 43 | t.Errorf("%d [%016b] != %d [%016b]", ans, ans, tp.want, tp.want) 44 | } 45 | }) 46 | } 47 | 48 | func TestLeftShift(t *testing.T) { 49 | tp := struct { 50 | a, b uint16 51 | want uint16 52 | }{8, 2, 32} 53 | t.Run(fmt.Sprintf("%d,%d", tp.a, tp.b), func(*testing.T) { 54 | ans := LeftShift(tp.a, tp.b) 55 | if ans != tp.want { 56 | t.Errorf("%d [%016b] != %d [%016b]", ans, ans, tp.want, tp.want) 57 | } 58 | }) 59 | } 60 | 61 | func TestRightShift(t *testing.T) { 62 | tp := struct { 63 | a, b uint16 64 | want uint16 65 | }{8, 2, 2} 66 | t.Run(fmt.Sprintf("%d,%d", tp.a, tp.b), func(*testing.T) { 67 | ans := RightShift(tp.a, tp.b) 68 | if ans != tp.want { 69 | t.Errorf("%d [%016b] != %d [%016b]", ans, ans, tp.want, tp.want) 70 | } 71 | }) 72 | } 73 | 74 | func TestTestBit(t *testing.T) { 75 | testName8 := fmt.Sprintf("%d,%d", 193, 0) 76 | testName16 := fmt.Sprintf("%d,%d", 0xFFFE, 1) 77 | testName32 := fmt.Sprintf("%d,%d", 0xFFFFFFFE, 6) 78 | testName64 := fmt.Sprintf("%d,%d", 1, 64) 79 | testNameErr := fmt.Sprintf("%.2f,1", 1.0) 80 | t.Run(testName8, func(*testing.T) { 81 | ans, err := TestBit(uint8(193), 0) 82 | if ans != true && err != nil { 83 | t.Errorf("Expected true with nil error, got %v [%v]", ans, err) 84 | } 85 | }) 86 | t.Run(testName16, func(*testing.T) { 87 | ans, err := TestBit(uint16(0xFFFE), 1) 88 | if ans != true && err != nil { 89 | t.Errorf("Expected true with nil error, got %v [%v]", ans, err) 90 | } 91 | }) 92 | t.Run(testName32, func(*testing.T) { 93 | ans, err := TestBit(uint32(0xFFFFFFFE), 6) 94 | if ans != true && err != nil { 95 | t.Errorf("Expected true with nil error, got %v [%v]", ans, err) 96 | } 97 | }) 98 | t.Run(testName64, func(*testing.T) { 99 | ans, err := TestBit(uint64(1), 0) 100 | if ans != true && err != nil { 101 | t.Errorf("Expected true with nil error, got %v [%v]", ans, err) 102 | } 103 | }) 104 | t.Run(testNameErr, func(*testing.T) { 105 | ans, err := TestBit(1.0, 0) 106 | if ans != false || err == nil { 107 | t.Errorf("Expected false with error, got %v [%v]", ans, err) 108 | } 109 | }) 110 | } 111 | -------------------------------------------------------------------------------- /binary_routines/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This package contains demonstration code and comments for various binary level routines. 4 | // It is designed show how binary operators work, and how we can perform various operations with 5 | // those operators. 6 | -------------------------------------------------------------------------------- /functions/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This folder contains code to demonstrate various functions and methods and how they 4 | // work 5 | -------------------------------------------------------------------------------- /functions/functions.go: -------------------------------------------------------------------------------- 1 | // Functions and methods example code 2 | // Andrew Alston 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | // BasicFunction demonstrates the declaration of a basic function that takes two 9 | // integer arguments and returns an integer. In this case because the two 10 | // input variables are of the same type, we can specify the type just once. 11 | func BasicFunction(a, b int) int { 12 | return a * b 13 | } 14 | 15 | // BasicFunctionDualReturn demonstrates the declaration of a basic function that 16 | // returns both a boolean value and an error type, as with BasicFunction, it takes two 17 | // integer inputs and returns true with a nil error if a > b, false with a nil error if a < b, 18 | // and false with an error if a == b 19 | func BasicFunctionDualReturn(a, b int) (bool, error) { 20 | if a == b { 21 | return false, fmt.Errorf("error, a and b were equal") 22 | } 23 | return a > b, nil 24 | } 25 | 26 | // NestedAnonymous demonstrates the creation of an anonymous function inside a containing function 27 | // The anonymous function is called by calling the variable name to which the anonymous function 28 | // is assigned 29 | func NestedAnonymous(a, b int) (int, int) { 30 | Multiply := func(num1, num2 int) int { 31 | return num1 * num2 32 | } 33 | Divide := func(num1, num2 int) int { 34 | return num1 / num2 35 | } 36 | retM := Multiply(a, b) 37 | retD := Divide(a, b) 38 | return retM, retD 39 | } 40 | 41 | // DemoStruct defines a structure that we will tie methods to as a demonstration of how methods 42 | // work 43 | type DemoStruct struct { 44 | a int 45 | b int 46 | } 47 | 48 | // Multiply is a method of DemoStruct and returns the two elements contained in the structure 49 | // multiplied by each other 50 | func (ds *DemoStruct) Multiply() int { 51 | return ds.a * ds.b 52 | } 53 | 54 | // String is a method we attach to DemoStruct to demonstrate how we can attach a method to a structure 55 | // that performs a specific function that can be handled by things like fmt.Printf 56 | func (ds *DemoStruct) String() string { 57 | return fmt.Sprintf("Struct contains A: %d and B: %d\n", ds.a, ds.b) 58 | } 59 | 60 | // SliceReceiver is a slice type we will use to demonstrate working with a slice that is passed as 61 | // a function receiver 62 | type SliceReceiver []int 63 | 64 | // AppendSlice appends to the slice receiver. Note - since by the golang spec you cannot assign to, 65 | // or change the receiver using a method, we pass the slice as a pointer and append to the de-referenced 66 | // slice. In this case we use a varadic argument so we can append multiple integers at the same time, 67 | // and then expand the varadic in the append function 68 | func (sr *SliceReceiver) Append(a ...int) { 69 | if len(a) > 0 { 70 | *sr = append(*sr, a...) 71 | } 72 | } 73 | 74 | // DeleteElementNoOrder deletes an element at offset x from the receiver. This method will result in 75 | // the ordering of the slice changing since it does the deletion by swapping the specified element with 76 | // the last element of the slice, and then popping the last element off the slice. If x is larger 77 | // than the length of the slice an error is returned. As a note: Since we need to refer to index entries 78 | // within the receiver - we must de-reference the pointer and then index. We place the receiver in 79 | // () during this, since *sr[x] says to de-reference the element at sr[x] rather than saying return 80 | // the element at index x of the slice 81 | func (sr *SliceReceiver) DeleteElementNoOrder(x int) error { 82 | if x > len(*sr)-1 { 83 | return fmt.Errorf("x is out of range on the receiver") 84 | } 85 | // Swap the last element and the element we want to remove 86 | (*sr)[x], (*sr)[len(*sr)-1] = (*sr)[len(*sr)-1], (*sr)[x] 87 | // Pop the last element off the slice post swap 88 | *sr = (*sr)[:len(*sr)-1] 89 | return nil 90 | } 91 | 92 | func main() { 93 | fmt.Printf("Calling BasicFunction with arguments 2 and 3 returns %d\n", BasicFunction(2, 3)) 94 | 95 | // Note: calling the function in this method makes both result and err scope local and as such 96 | // they will not be available outside of the if statement. If we wish to use the results later 97 | // we can either do result, err := BasicFunctionDualReturns(2,3) and then reference the resulting 98 | // variables or setup the variables as var's and call if result,err = BasicFunctionDualReturn(2, 3)... 99 | fmt.Printf("\nDemonstrating dual returns:\n") 100 | if result, err := BasicFunctionDualReturn(2, 3); err != nil { 101 | fmt.Printf("Error: %v\n", err) 102 | } else { 103 | fmt.Printf("Result of calling BasicFunctionDualReturn with arguments 2 and 3 was %v\n", result) 104 | } 105 | 106 | fmt.Printf("\nDemonstrating nested anonymous functions\n") 107 | retM, retD := NestedAnonymous(10, 5) 108 | fmt.Printf("Anonymous Multiply: %d\nAnonymous Divide: %d\n", retM, retD) 109 | 110 | fmt.Printf("\nDemonstrating struct methods\n") 111 | // First we create a variable of type DemoStruct and fill its elements. Note we are creating a pointer 112 | // here - and the below line is the equivalent of doing demoVar := new(DemoStruct) and then filling 113 | // in the elements later. 114 | demoVar := &DemoStruct{a: 1, b: 2} 115 | fmt.Printf("Since DemoStruct has a string method we can print its contents like this:\n%v\n", demoVar.String()) 116 | fmt.Printf("Multiplying the elements contained in demoVar as a result of: %d\n", demoVar.Multiply()) 117 | 118 | // This next section creates a slice an empty slice of integers and then appends some numbers to it 119 | // For this - we make an empty slice, and then tell the compiler this is of type SliceReceiver 120 | fmt.Printf("\nDemonstrating slice receivers\n") 121 | var a = SliceReceiver(make([]int, 0)) 122 | (&a).Append(1, 2, 3, 4) 123 | fmt.Printf("Our slice now contains: %v\n", a) 124 | fmt.Printf("Deleting element 2 from our slice\n") 125 | if err := (&a).DeleteElementNoOrder(2); err != nil { 126 | fmt.Printf("%v\n", err) 127 | } else { 128 | fmt.Printf("Slice element deleted, slice now contains: %v\n", a) 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /functions/functions_test.go: -------------------------------------------------------------------------------- 1 | // Functions and methods test routines 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestBasicFunction(t *testing.T) { 10 | tests := []struct { 11 | a, b int 12 | want int 13 | }{ 14 | {1, 3, 3}, 15 | {2, 3, 6}, 16 | {3, 3, 9}, 17 | {5, 3, 15}, 18 | {5, 5, 25}, 19 | } 20 | for _, tt := range tests { 21 | testName := fmt.Sprintf("%d,%d", tt.a, tt.b) 22 | t.Run(testName, func(t *testing.T) { 23 | ans := BasicFunction(tt.a, tt.b) 24 | if tt.want != ans { 25 | t.Errorf("got %d while wanting %d", ans, tt.want) 26 | } 27 | }) 28 | } 29 | } 30 | 31 | func TestBasicFunctionDualReturn(t *testing.T) { 32 | tests := []struct { 33 | a, b int 34 | want1 bool 35 | want2 error 36 | }{ 37 | {1, 1, false, fmt.Errorf("error, a and b were equal")}, 38 | {1, 2, false, nil}, 39 | {2, 1, true, nil}, 40 | } 41 | for _, tt := range tests { 42 | testName := fmt.Sprintf("%d,%d", tt.a, tt.b) 43 | t.Run(testName, func(t *testing.T) { 44 | b, e := BasicFunctionDualReturn(tt.a, tt.b) 45 | if b != tt.want1 { 46 | t.Errorf("wanted boolean %v got %v", b, tt.want1) 47 | } 48 | if e != nil && e.Error() != tt.want2.Error() { 49 | t.Errorf("wanted %v got %v", e, tt.want2) 50 | } 51 | }) 52 | } 53 | } 54 | 55 | func TestNestedAnonymous(t *testing.T) { 56 | tests := []struct { 57 | a, b int 58 | want1, want2 int 59 | }{ 60 | {10, 5, 50, 2}, 61 | {20, 5, 100, 4}, 62 | {100, 10, 1000, 10}, 63 | } 64 | for _, tt := range tests { 65 | testName := fmt.Sprintf("%d,%d", tt.a, tt.b) 66 | t.Run(testName, func(t *testing.T) { 67 | ans1, ans2 := NestedAnonymous(tt.a, tt.b) 68 | if tt.want1 != ans1 || tt.want2 != ans2 { 69 | t.Errorf("got %d and %d while wanting %d and %d", ans1, ans2, tt.want1, tt.want2) 70 | } 71 | }) 72 | } 73 | } 74 | 75 | func TestDemoStruct_Multiply(t *testing.T) { 76 | tests := []struct { 77 | a *DemoStruct 78 | want int 79 | }{ 80 | {&DemoStruct{a: 1, b: 2}, 2}, 81 | {&DemoStruct{a: 5, b: 10}, 50}, 82 | {&DemoStruct{a: 7, b: 3}, 21}, 83 | } 84 | for _, tt := range tests { 85 | testName := fmt.Sprintf("%+v", tt.a) 86 | t.Run(testName, func(t *testing.T) { 87 | ans := tt.a.Multiply() 88 | if tt.want != ans { 89 | t.Errorf("got %d while wanting %d", ans, tt.want) 90 | } 91 | }) 92 | } 93 | } 94 | 95 | func TestSliceReceiver_Append(t *testing.T) { 96 | tests := []struct { 97 | sr *SliceReceiver 98 | a []int 99 | want []int 100 | }{ 101 | {&SliceReceiver{1, 2}, []int{3, 4, 5}, []int{1, 2, 3, 4, 5}}, 102 | {&SliceReceiver{1, 2, 3, 4}, []int{5, 6, 7}, []int{1, 2, 3, 4, 5, 6, 7}}, 103 | {&SliceReceiver{1, 3, 5}, []int{7, 9, 11}, []int{1, 3, 5, 7, 9, 11}}, 104 | } 105 | for _, tt := range tests { 106 | testName := fmt.Sprintf("%v,%v", *tt.sr, tt.a) 107 | t.Run(testName, func(t *testing.T) { 108 | tt.sr.Append(tt.a...) 109 | ans := []int(*tt.sr) 110 | if len(ans) != len(tt.want) { 111 | t.Errorf("length of receiver != %d", len(tt.want)) 112 | } 113 | for a := range ans { 114 | if ans[a] != tt.want[a] { 115 | t.Errorf("%d at offset %d != %d", ans[a], a, tt.want[a]) 116 | } 117 | } 118 | }) 119 | } 120 | } 121 | 122 | func TestSliceReceiver_DeleteElementNoOrder(t *testing.T) { 123 | tests := []struct { 124 | sr *SliceReceiver 125 | a int 126 | want []int 127 | }{ 128 | {&SliceReceiver{1, 5, 7, 9, 11}, 1, []int{1, 11, 7, 9}}, 129 | {&SliceReceiver{1, 5, 7, 9, 11}, 4, []int{1, 5, 7, 9}}, 130 | {&SliceReceiver{1, 5, 7, 9, 11}, 0, []int{11, 5, 7, 9}}, 131 | } 132 | 133 | for _, tt := range tests { 134 | testName := fmt.Sprintf("%v,%d", *tt.sr, tt.a) 135 | t.Run(testName, func(*testing.T) { 136 | err := tt.sr.DeleteElementNoOrder(tt.a) 137 | if err != nil { 138 | t.Errorf("error: %v", err) 139 | return 140 | } 141 | ans := []int(*tt.sr) 142 | if len(ans) != len(tt.want) { 143 | t.Errorf("length of receiver != %d", len(tt.want)) 144 | return 145 | } 146 | for i := 0; i < len(ans)-1; i++ { 147 | if ans[i] != tt.want[i] { 148 | t.Errorf("%d at offset %d != %d", ans[i], i, tt.want[i]) 149 | return 150 | } 151 | } 152 | }) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /pointers/pointers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | // PointerNoReturn takes 3 arguments, and returns the result of a multiplied by b into 9 | // the integer pointed to by c 10 | func PointerNoReturn(a, b int, c *int) { 11 | *c = a * b 12 | } 13 | 14 | // PointerByteSwap takes a single uint16 pointer swaps the underlying byte order of the 15 | // uint16 pointed to by the input number 16 | func PointerByteSwap(a *uint16) { 17 | *a = (*a << 8) | (*a >> 8) 18 | } 19 | 20 | // ReturnByte returns a single byte at position b from one of the four bytes that comprise 21 | // the uint32 passed in as a 22 | func ReturnByte(a uint32, b uint8) (uint8, error) { 23 | if b >= 3 { 24 | return 0, fmt.Errorf("byte out of range") 25 | } 26 | return *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&a)) + uintptr(b))), nil 27 | } 28 | 29 | // ReturnUint32FromSlice returns a single uint32 comprising of 4 sequential bytes 30 | // in slice a, starting at reference position b 31 | func ReturnUint32FromSlice(a []uint8, b int) (uint32, error) { 32 | if len(a) <= 3 { 33 | return 0, fmt.Errorf("insufficient bytes in slice") 34 | } 35 | return *(*uint32)(unsafe.Pointer(&a[b])), nil 36 | } 37 | 38 | // ModifySlicePointer appends the variadic b to the slice referenced by pointer a 39 | func ModifySlicePointer(a *[]uint8, b ...uint8) { 40 | *a = append(*a, b...) 41 | } 42 | 43 | // IndexSlicePointer returns the byte at position b from the slice pointed to by a 44 | func IndexSlicePointer(a *[]uint8, b int) (uint8, error) { 45 | if len(*a)-1 <= b { 46 | return 0, fmt.Errorf("byte not within slice range") 47 | } 48 | return (*a)[b], nil 49 | } 50 | 51 | func main() { 52 | // Various test variables 53 | var IntVar int 54 | var Uint16Var uint16 55 | var Uint32Var uint32 = 0xFFFEFDFC 56 | var ByteSlice = []uint8{1, 2, 3, 4} 57 | var ByteSlice2 = []uint8{5, 6, 7, 8} 58 | 59 | // Set IntVar by passing the pointer to the PointerNoReturn Function 60 | PointerNoReturn(300, 300, &IntVar) 61 | fmt.Printf("%d * %d placed in IntVar, result was %d\n", 300, 300, IntVar) 62 | 63 | // Swap the byte order of IntVar 64 | Uint16Var = uint16(IntVar) 65 | fmt.Printf("Swapping byte order of %0X\n", Uint16Var) 66 | PointerByteSwap(&Uint16Var) 67 | fmt.Printf("Uint16Var is now %0X\n", Uint16Var) 68 | 69 | x, _ := ReturnByte(Uint32Var, 2) 70 | fmt.Printf("Byte 2 of %0X is %0X\n", Uint32Var, x) 71 | 72 | // As a bonus question for discussion - note the byte order of the generated uint32 73 | y, _ := ReturnUint32FromSlice([]uint8{1, 2, 3, 4}, 0) 74 | fmt.Printf("Uint32 generated from byte slice %v at offset 0 is %0X\n", ByteSlice, y) 75 | 76 | fmt.Printf("Appending %v to %v...\n", ByteSlice, ByteSlice2) 77 | ModifySlicePointer(&ByteSlice, ByteSlice2...) 78 | fmt.Printf("ByteSlice is now %v\n", ByteSlice) 79 | 80 | ret, _ := IndexSlicePointer(&ByteSlice, 2) 81 | fmt.Printf("Byte at position 2 of ByteSlice is %d\n", ret) 82 | } 83 | -------------------------------------------------------------------------------- /prime_numbers_1/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This package contains demonstration code to calculate prime numbers in a set range. 4 | // It should be noted that this is not the most efficient method of doing this, and that 5 | // will be covered in a subsequent example 6 | -------------------------------------------------------------------------------- /prime_numbers_1/prime.go: -------------------------------------------------------------------------------- 1 | // Basic golang training, prime number locator (method 1) 2 | // Andrew Alston 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "fmt" 9 | "time" 10 | ) 11 | 12 | func FindPrime(Min, Max int) []int { 13 | // IsPrime is a boolean we will use to track if a number is or isn't prime on our inner loop 14 | var IsPrime bool 15 | // res is our slice of integers to store the prime numbers in for return, 16 | var res []int 17 | 18 | // Our outer loop 19 | for i := Min; i < Max; i++ { 20 | // Assume that i is a prime number at the start of each iteration 21 | IsPrime = true 22 | // Since anything divided by a number greater than half of itself is always going to produce 23 | // a non-zero remainder - we can run the loop to half of our input number 24 | for j := 2; j <= i/2; j++ { 25 | if i%j == 0 { 26 | // The moment we find a clean division, we can break out of the inner loop, 27 | // after setting the variable to tell us that this isn't a prime number 28 | IsPrime = false 29 | break 30 | } 31 | } 32 | // If this isn't a prime number, append it to our result list 33 | if IsPrime { 34 | res = append(res, i) 35 | } 36 | } 37 | // Finally return the result list 38 | return res 39 | } 40 | 41 | func main() { 42 | var StartTime time.Time 43 | 44 | // These are our CLI flags - they can be specified in any order on the command line. 45 | // The first variable specified in the cli flag itself, the second is the default for the flag, the third 46 | // is the help for the flag itself and is what is shown when you print the defaults 47 | Minimum := flag.Int("min", 2, "Minimum number in range to search for primes") 48 | Maximum := flag.Int("max", 4000, "Maximum number in range to search for primes") 49 | DumpPrimes := flag.Bool("dump-prime", false, "Dump the list of prime numbers located") 50 | TimeExecution := flag.Bool("timing", false, "Dump the execution and prime the results") 51 | flag.Parse() 52 | 53 | // Note: flags are always pointers, so we have to de-reference them, hence the asterix 54 | if *Minimum > *Maximum || *Minimum == *Maximum { 55 | fmt.Printf("Minimum in range must be smaller than range maximum") 56 | flag.PrintDefaults() 57 | return 58 | } 59 | if *Minimum < 2 { 60 | fmt.Printf("Please specify a minimum number greater than or equal to two\n") 61 | flag.PrintDefaults() 62 | return 63 | } 64 | 65 | // If our timing flag is set - grab the start time before we start looking for the prime numbers 66 | if *TimeExecution { 67 | StartTime = time.Now() 68 | } 69 | 70 | // Find the prime numbers calling our FindPrime function with our minimum and maximum arguments 71 | results := FindPrime(*Minimum, *Maximum) 72 | 73 | // If our timing flag is set - prime the time its taken to find all our prime numbers 74 | if *TimeExecution { 75 | fmt.Printf("Took us %s to find all primes in a range of %d numbers\n", time.Since(StartTime), *Maximum-*Minimum) 76 | } 77 | fmt.Printf("Found %d prime numbers between %d and %d\n", len(results), *Minimum, *Maximum) 78 | 79 | // If our dump flag is set - dump the list of located prime numbers 80 | if *DumpPrimes { 81 | fmt.Printf("Located the following prime numbers in the range %d -> %d\n", *Minimum, *Maximum) 82 | for i, p := range results { 83 | // \t is an escape code for a tab 84 | // \n is a new line character 85 | // %d tells us that the variable or constant being referenced is an integer 86 | // If we wanted to print a float, that would be a %f - more about number formatting later 87 | fmt.Printf("\t[%d]: %d\n", i, p) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /prime_numbers_1/prime_test.go: -------------------------------------------------------------------------------- 1 | // Prime number test routine 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestFindPrime(t *testing.T) { 10 | var tests = []struct { 11 | a, b int 12 | want []int 13 | }{ 14 | {2, 20, []int{2, 3, 5, 7, 11, 13, 17, 19}}, 15 | {20, 40, []int{23, 29, 31, 17}}, 16 | {40, 60, []int{41, 43, 47, 53, 59}}, 17 | } 18 | for _, tt := range tests { 19 | testName := fmt.Sprintf("Min: %2d\tMax: %2d", tt.a, tt.b) 20 | t.Run(testName, func(t *testing.T) { 21 | ans := FindPrime(tt.a, tt.b) 22 | if len(ans) != len(tt.want) { 23 | t.Errorf("got %v instead of %v", ans, tt.want) 24 | } 25 | for i := 0; i < len(ans)-1; i++ { 26 | if ans[i] != tt.want[i] { 27 | t.Errorf("got %v instead of %v", ans, tt.want) 28 | } 29 | } 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /prime_numbers_sieve/doc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This package contains demonstration code to calculate prime numbers in a range to the specified maximum. 4 | // This implementation uses the Sieve of Eratosthenes algorithm and is hence far more efficient than 5 | // the implementation in the prime_numbers_1 routine 6 | -------------------------------------------------------------------------------- /prime_numbers_sieve/prime_sieve.go: -------------------------------------------------------------------------------- 1 | // Basic golang training, prime number locator (Sieve method 1) 2 | // Andrew Alston 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "fmt" 9 | "time" 10 | ) 11 | 12 | func Sieve(max int) []int { 13 | // Initialize this as an array of uint8's to save memory and save a loop 14 | // needed to flip the array, this will be initialized as everything 0 15 | intArray := make([]uint8, max+1) 16 | 17 | // Start with 2, and keep going until the number being tested squared is greater than the maximum number 18 | for p := 2; p*p <= max; p++ { 19 | // Check if the array position referenced by the prime we are testing is unchanged, if it is, 20 | // the number is a prime number 21 | if intArray[p] == 0 { 22 | // Change all multiples of the number to state that they arent prime numbers 23 | for i := p * 2; i <= max; i += p { 24 | intArray[i] = 1 25 | } 26 | } 27 | } 28 | // Iterate through the array adding anything that is a prime to our results array 29 | var primes []int 30 | for p := 2; p <= max; p++ { 31 | if intArray[p] == 0 { 32 | primes = append(primes, p) 33 | } 34 | } 35 | // Return the resulting array 36 | return primes 37 | } 38 | 39 | func main() { 40 | var StartTime time.Time 41 | 42 | Maximum := flag.Int("max", 4000, "Maximum number in range to search for primes") 43 | DumpPrimes := flag.Bool("dump-prime", false, "Dump the list of prime numbers located") 44 | TimeExecution := flag.Bool("timing", false, "Dump the execution and prime the results") 45 | flag.Parse() 46 | 47 | // Note: flags are always pointers, so we have to de-reference them, hence the asterix 48 | if *Maximum < 2 { 49 | fmt.Printf("Maximum must be a number larger than 1\n") 50 | flag.PrintDefaults() 51 | return 52 | } 53 | 54 | // If our timing flag is set - grab the start time before we start looking for the prime numbers 55 | if *TimeExecution { 56 | StartTime = time.Now() 57 | } 58 | 59 | // Find the prime numbers calling our FindPrime function with our minimum and maximum arguments 60 | results := Sieve(*Maximum) 61 | 62 | // If our timing flag is set - prime the time its taken to find all our prime numbers 63 | if *TimeExecution { 64 | fmt.Printf("Took us %s to find all primes in a range of %d numbers\n", time.Since(StartTime), *Maximum-2) 65 | } 66 | fmt.Printf("Found %d prime numbers between 2 and %d\n", len(results), *Maximum) 67 | 68 | // If our dump flag is set - dump the list of located prime numbers 69 | if *DumpPrimes { 70 | fmt.Printf("Located the following prime numbers in the range 2 -> %d\n", *Maximum) 71 | for i, p := range results { 72 | // \t is an escape code for a tab 73 | // \n is a new line character 74 | // %d tells us that the variable or constant being referenced is an integer 75 | // If we wanted to print a float, that would be a %f - more about number formatting later 76 | fmt.Printf("\t[%d]: %d\n", i, p) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /prime_numbers_sieve/prime_sieve_test.go: -------------------------------------------------------------------------------- 1 | // Prime Sieve test routines 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestSieve(t *testing.T) { 10 | tests := []struct { 11 | a int 12 | want []int 13 | }{ 14 | {10, []int{2, 3, 5, 7}}, 15 | {20, []int{2, 3, 5, 7, 11, 13, 17, 19}}, 16 | {50, []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47}}, 17 | {200, []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 18 | 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 19 | 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 20 | 191, 193, 197, 199}}, 21 | {1000, []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 22 | 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 23 | 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 24 | 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 25 | 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 26 | 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 27 | 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 28 | 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 29 | 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 30 | 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 31 | 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 32 | 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 33 | 947, 953, 967, 971, 977, 983, 991, 997}}, 34 | } 35 | for _, tt := range tests { 36 | testName := fmt.Sprintf("Max: %2d", tt.a) 37 | t.Run(testName, func(t *testing.T) { 38 | ans := Sieve(tt.a) 39 | if len(ans) != len(tt.want) { 40 | t.Errorf("got %v instead of %v", ans, tt.want) 41 | } 42 | for i := 0; i < len(ans)-1; i++ { 43 | if ans[i] != tt.want[i] { 44 | t.Errorf("got %v instead of %v", ans, tt.want) 45 | } 46 | } 47 | }) 48 | } 49 | } 50 | --------------------------------------------------------------------------------