From e5242e2c08857e0450e42b767d8c6c9028eea18f Mon Sep 17 00:00:00 2001 From: Alokzh Date: Sat, 12 Jul 2025 10:09:10 +0530 Subject: [PATCH 1/3] Improved basic initialisation & accessor methods with tests --- .../BaselineOfContainersStack.class.st | 9 +- src/BaselineOfContainersStack/package.st | 2 +- .../CTStackTest.class.st | 321 +++++++++--------- src/Containers-Stack-Tests/package.st | 2 +- src/Containers-Stack/CTStack.class.st | 131 +++---- src/Containers-Stack/package.st | 2 +- 6 files changed, 241 insertions(+), 226 deletions(-) diff --git a/src/BaselineOfContainersStack/BaselineOfContainersStack.class.st b/src/BaselineOfContainersStack/BaselineOfContainersStack.class.st index 9c0384c..98211ce 100644 --- a/src/BaselineOfContainersStack/BaselineOfContainersStack.class.st +++ b/src/BaselineOfContainersStack/BaselineOfContainersStack.class.st @@ -1,10 +1,11 @@ Class { - #name : #BaselineOfContainersStack, - #superclass : #BaselineOf, - #category : #BaselineOfContainersStack + #name : 'BaselineOfContainersStack', + #superclass : 'BaselineOf', + #category : 'BaselineOfContainersStack', + #package : 'BaselineOfContainersStack' } -{ #category : #baseline } +{ #category : 'baselines' } BaselineOfContainersStack >> baseline: spec [ diff --git a/src/BaselineOfContainersStack/package.st b/src/BaselineOfContainersStack/package.st index 2bfd7fc..0b5f8a8 100644 --- a/src/BaselineOfContainersStack/package.st +++ b/src/BaselineOfContainersStack/package.st @@ -1 +1 @@ -Package { #name : #BaselineOfContainersStack } +Package { #name : 'BaselineOfContainersStack' } diff --git a/src/Containers-Stack-Tests/CTStackTest.class.st b/src/Containers-Stack-Tests/CTStackTest.class.st index 089c152..cbd8d77 100644 --- a/src/Containers-Stack-Tests/CTStackTest.class.st +++ b/src/Containers-Stack-Tests/CTStackTest.class.st @@ -1,219 +1,232 @@ Class { - #name : #CTStackTest, - #superclass : #TestCase, + #name : 'CTStackTest', + #superclass : 'TestCase', #instVars : [ - 'empty', - 'nonEmpty' + 'stack' ], - #category : #'Containers-Stack-Tests' + #category : 'Containers-Stack-Tests', + #package : 'Containers-Stack-Tests' } -{ #category : #requirements } -CTStackTest >> empty [ - - ^ empty +{ #category : 'running' } +CTStackTest >> setUp [ + super setUp. + stack := CTStack new: 5 ] -{ #category : #requirements } -CTStackTest >> nonEmpty [ - - ^ nonEmpty -] +{ #category : 'tests' } +CTStackTest >> testAlternatingPushPop [ -{ #category : #setup } -CTStackTest >> setUp [ - super setUp. - empty := self stackClass new. - nonEmpty := self stackClass new. - nonEmpty push: 1. - nonEmpty push: -2. - nonEmpty push: 3. - nonEmpty push: 1. + stack push: 'a'. + self assert: stack pop equals: 'a'. + + stack push: 'b'; push: 'c'. + self assert: stack pop equals: 'c'. + stack push: 'd'. + self assert: stack top equals: 'd'. + self assert: stack size equals: 2 ] -{ #category : #setup } -CTStackTest >> stackClass [ +{ #category : 'tests' } +CTStackTest >> testAvailableSpace [ - ^ CTStack + self assert: stack availableSpace equals: 5. + stack push: 'a'. + self assert: stack availableSpace equals: 4. + stack push: 'b'; push: 'c'. + self assert: stack availableSpace equals: 2. + stack pop. + self assert: stack availableSpace equals: 3 ] -{ #category : #tests } -CTStackTest >> testCapacity [ +{ #category : 'tests' } +CTStackTest >> testCapacity [ - | aStack | - aStack := self stackClass new. - self assert: aStack capacity equals: OrderedCollection new capacity. - + self assert: stack capacity equals: 5. + stack push: 'test'. + self assert: stack capacity equals: 5. "Capacity doesn't change" ] -{ #category : #tests } -CTStackTest >> testCapacityWhenGrowing [ +{ #category : 'tests' } +CTStackTest >> testDefaultStackCreation [ - | aStack | - aStack := self stackClass new. - aStack - push: 1; push: 2; push: 3; push: 4; push: 5; - push: 6; push: 7; push: 8; push: 9 ; push: 10. - self assert: aStack capacity equals: OrderedCollection new capacity. - aStack push: 11. - self deny: aStack capacity equals: OrderedCollection new capacity + | defaultStack | + defaultStack := CTStack new. + + self assert: defaultStack capacity equals: 10. + self assert: defaultStack isEmpty. + self assert: defaultStack size equals: 0. + self assert: defaultStack availableSpace equals: 10 ] -{ #category : #tests } -CTStackTest >> testCopyCreatesANewObject [ +{ #category : 'tests' } +CTStackTest >> testIsEmpty [ - | copy | - copy := self nonEmpty copy. - self deny: self nonEmpty == copy + self assert: stack isEmpty. + stack push: 'test'. + self deny: stack isEmpty. + stack pop. + self assert: stack isEmpty ] -{ #category : #tests } -CTStackTest >> testCopyEmpty [ +{ #category : 'tests' } +CTStackTest >> testIsFull [ - | copy | - copy := self empty copy. - self assert: copy isEmpty + self deny: stack isFull. + stack push: 'a'; push: 'b'; push: 'c'; push: 'd'; push: 'e'. + self assert: stack isFull. + stack pop. + self deny: stack isFull ] -{ #category : #tests } -CTStackTest >> testEmptyError [ +{ #category : 'tests' } +CTStackTest >> testPopMultipleElements [ - | aStack | - aStack := self stackClass new. - self should: [ aStack top ] raise: Error. - self should: [ aStack pop ] raise: Error. - aStack push: 'element'. - aStack top. - aStack pop. "The stack is empty again due to previous pop" - self should: [ aStack top ] raise: Error. - self should: [ aStack pop ] raise: Error + stack push: 'first'; push: 'second'; push: 'third'. + + self assert: stack pop equals: 'third'. + self assert: stack pop equals: 'second'. + self assert: stack size equals: 1. + self assert: stack top equals: 'first' ] -{ #category : #tests } -CTStackTest >> testIfEmpty [ +{ #category : 'tests' } +CTStackTest >> testPopSingleElement [ - | aStack | - aStack := self stackClass new. - self assert: (aStack ifEmpty: [ true ]). - aStack push: 11. - self assert: (aStack ifEmpty: [ 1/0 ]) == aStack + | element | + stack push: 'test'. + element := stack pop. + + self assert: element equals: 'test'. + self assert: stack isEmpty. + self assert: stack size equals: 0. + self assert: stack availableSpace equals: 5 ] -{ #category : #tests } -CTStackTest >> testIfEmptyIfNotEmpty [ +{ #category : 'tests' } +CTStackTest >> testPushAllOverflow [ - | aStack | - aStack := self stackClass new. - self assert: (aStack ifEmpty: [ true ] ifNotEmpty: [ 1/0 ]). - aStack push: 11. - self assert: (aStack ifEmpty: [ 1/0 ] ifNotEmpty: [ true ]) + stack push: 'existing'. + + self should: [ stack pushAll: #('a' 'b' 'c' 'd' 'e') ] raise: Error ] -{ #category : #tests } -CTStackTest >> testIfNotEmpty [ +{ #category : 'tests' } +CTStackTest >> testPushAllWithArray [ - | aStack | - aStack := self stackClass new. - self assert: (aStack ifNotEmpty: [ 1/0 ]) == aStack. - aStack push: 11. - self assert: (aStack ifNotEmpty: [ true ]) + | result | + result := stack pushAll: #('a' 'b' 'c'). + + self assert: stack size equals: 3. + self assert: result equals: 'c'. + self assert: stack top equals: 'c' ] -{ #category : #tests } -CTStackTest >> testIfNotEmptyIfEmpty [ +{ #category : 'tests' } +CTStackTest >> testPushAllWithEmptyCollection [ - | aStack | - aStack := self stackClass new. - self assert: (aStack ifNotEmpty: [ 1/0 ] ifEmpty: [ true ]). - aStack push: 11. - self assert: (aStack ifNotEmpty: [ true ] ifEmpty: [ 1/0 ]) + | result | + result := stack pushAll: #(). + + self assert: stack size equals: 0. + self assert: result isNil. + self assert: stack isEmpty ] -{ #category : #tests } -CTStackTest >> testIsEmpty [ - - | aStack | - aStack := self stackClass new. - self assert: aStack isEmpty. - aStack push: 1. - self deny: aStack isEmpty +{ #category : 'tests' } +CTStackTest >> testPushAllWithOrderedCollection [ + | collection result | + collection := OrderedCollection with: 'x' with: 'y' with: 'z'. + result := stack pushAll: collection. + + self assert: stack size equals: 3. + self assert: result equals: 'z'. + self assert: stack top equals: 'z' ] -{ #category : #tests } -CTStackTest >> testPop [ +{ #category : 'tests' } +CTStackTest >> testPushMultipleElements [ - | aStack res elem | - elem := 'anElement'. - aStack := self stackClass new. - self assert: aStack isEmpty. - - aStack push: 'a'. - aStack push: elem. - res := aStack pop. - self assert: res equals: elem. - self assert: res == elem. + stack push: 'first'; push: 'second'; push: 'third'. - self assert: aStack size equals: 1. - aStack pop. - self assert: aStack isEmpty. + self assert: stack size equals: 3. + self assert: stack top equals: 'third'. + self assert: stack availableSpace equals: 2. + self deny: stack isEmpty. + self deny: stack isFull +] +{ #category : 'tests' } +CTStackTest >> testPushSingleElement [ + stack push: 'first'. + + self assert: stack size equals: 1. + self deny: stack isEmpty. + self deny: stack isFull. + self assert: stack top equals: 'first'. + self assert: stack availableSpace equals: 4 ] -{ #category : #tests } -CTStackTest >> testPreAllocateIntern [ +{ #category : 'tests' } +CTStackTest >> testPushToCapacity [ - | aStack | - aStack := self stackClass new: 1000. - self assert: aStack capacity equals: 1000. + stack push: 'a'; push: 'b'; push: 'c'; push: 'd'; push: 'e'. + self assert: stack size equals: 5. + self assert: stack isFull. + self assert: stack availableSpace equals: 0. + self assert: stack top equals: 'e' ] -{ #category : #tests } -CTStackTest >> testPush [ - - | aStack | - aStack := self stackClass new. - aStack push: 'a'. - self assert: aStack size = 1. - aStack push: 'b'. - self assert: aStack size = 2. +{ #category : 'tests' } +CTStackTest >> testPushToFullStack [ + + stack push: 'a'; push: 'b'; push: 'c'; push: 'd'; push: 'e'. + self should: [ stack push: 'overflow' ] raise: Error ] -{ #category : #tests } +{ #category : 'tests' } CTStackTest >> testSize [ - - | aStack | - aStack := self stackClass new. - self assert: aStack size equals: 0. - aStack push: 'a'. - self assert: aStack size equals: 1. - aStack push: 'b'. - self assert: aStack size equals: 2. - aStack pop. - self assert: aStack size equals: 1. - aStack pop. - self assert: aStack size equals: 0. - - - + self assert: stack size equals: 0. + stack push: 'a'. + self assert: stack size equals: 1. + stack push: 'b'; push: 'c'. + self assert: stack size equals: 3. + stack pop. + self assert: stack size equals: 2 +] + +{ #category : 'tests' } +CTStackTest >> testStackCreationWithCapacity [ + | testStack | + testStack := CTStack new: 3. + + self assert: testStack capacity equals: 3. + self assert: testStack isEmpty. + self assert: testStack size equals: 0. + self assert: testStack availableSpace equals: 3 +] +{ #category : 'tests' } +CTStackTest >> testStackCreationWithInvalidCapacity [ + + self should: [ CTStack new: 0 ] raise: Error. + self should: [ CTStack new: -1 ] raise: Error. + self should: [ CTStack new: -10 ] raise: Error ] -{ #category : #tests } -CTStackTest >> testTop [ +{ #category : 'tests' } +CTStackTest >> testTopWithoutRemoving [ - | aStack | - aStack := self stackClass new. - self assert: aStack isEmpty. - aStack push: 'a'. - aStack push: 'b'. - self assert: aStack top equals: 'b'. - self assert: aStack top equals: 'b'. - self assert: aStack size equals: 2. + stack push: 'first'; push: 'second'. + + self assert: stack top equals: 'second'. + self assert: stack size equals: 2. + self assert: stack top equals: 'second'. "Still there" ] diff --git a/src/Containers-Stack-Tests/package.st b/src/Containers-Stack-Tests/package.st index 113a6ef..7962891 100644 --- a/src/Containers-Stack-Tests/package.st +++ b/src/Containers-Stack-Tests/package.st @@ -1 +1 @@ -Package { #name : #'Containers-Stack-Tests' } +Package { #name : 'Containers-Stack-Tests' } diff --git a/src/Containers-Stack/CTStack.class.st b/src/Containers-Stack/CTStack.class.st index 88d02ac..884de28 100644 --- a/src/Containers-Stack/CTStack.class.st +++ b/src/Containers-Stack/CTStack.class.st @@ -6,109 +6,110 @@ I implement a simple Stack. - #top answer the first element of the stack without removing it. " Class { - #name : #CTStack, - #superclass : #Object, + #name : 'CTStack', + #superclass : 'Object', #instVars : [ - 'elements' + 'elements', + 'topIndex', + 'capacity' ], - #category : #'Containers-Stack' + #category : 'Containers-Stack', + #package : 'Containers-Stack' } -{ #category : #'instance creation' } -CTStack class >> new: aNumber [ +{ #category : 'instance creation' } +CTStack class >> new [ - ^ self basicNew - initializeWith: aNumber; - yourself - + "Create a new stack with default capacity of 10" + + ^ self new: 10 ] -{ #category : #query } -CTStack >> capacity [ +{ #category : 'instance creation' } +CTStack class >> new: anInteger [ - ^ elements capacity + anInteger < 1 ifTrue: [ self error: 'Capacity must be positive' ]. + ^ self basicNew + initializeWithCapacity: anInteger; + yourself ] -{ #category : #testing } -CTStack >> ifEmpty: aBlock [ - "If the receiver is empty execute the given block, returning its value, otherwise return the receiver." - - - "Note that the fact that this method returns its receiver in case the receiver is not empty allows one to write expressions like the following ones: self classifyMethodAs: (myProtocol ifEmpty: ['As yet unclassified'])" +{ #category : 'accessing' } +CTStack >> availableSpace [ - ^ elements ifEmpty: aBlock ifNotEmpty: [ self ] + ^ capacity - self size ] -{ #category : #testing } -CTStack >> ifEmpty: aBlockClosure ifNotEmpty: aBlockClosure2 [ - "Evaluate emptyBlock if I'm empty, evalute notEmptyBlock otherwise" - "If the notEmptyBlock has an argument, execute it using the receiver as its argument" +{ #category : 'accessing' } +CTStack >> capacity [ - - ^ elements ifEmpty: aBlockClosure ifNotEmpty: aBlockClosure2 + ^ capacity ] -{ #category : #testing } -CTStack >> ifNotEmpty: aBlock [ - "Evaluate the given block with the receiver as its argument, returning its value - unless the receiver is empty, in which case return the receiver." - +{ #category : 'initialization' } +CTStack >> initializeWithCapacity: anInteger [ - ^ elements ifNotEmpty: aBlock ifEmpty: [ self ] + capacity := anInteger. + elements := Array new: capacity. + topIndex := 0 ] -{ #category : #testing } -CTStack >> ifNotEmpty: aBlockClosure ifEmpty: aBlockClosure2 [ - "Evaluate emptyBlock if I'm empty, otherwise evaluate notEmptyBlock. - If the notEmptyBlock has an argument, execute with the receiver as its argument" - - ^ elements ifNotEmpty: aBlockClosure ifEmpty: aBlockClosure2 -] +{ #category : 'testing' } +CTStack >> isEmpty [ -{ #category : #initialization } -CTStack >> initialize [ - - super initialize. - elements := OrderedCollection new -] - -{ #category : #initialization } -CTStack >> initializeWith: aNumber [ - "Pre allocate the number of elements in the underlying data structure to avoid growing it multiple time when dealing with large stacks." + "Return true if stack has no elements" - elements := OrderedCollection new: aNumber + ^ topIndex = 0 ] -{ #category : #testing } -CTStack >> isEmpty [ +{ #category : 'testing' } +CTStack >> isFull [ + + "Return true if stack is at maximum capacity" - ^ elements isEmpty + ^ topIndex = capacity ] -{ #category : #operations } +{ #category : 'removing' } CTStack >> pop [ - "Returns the first element and removes it from the receiver." - ^ elements removeFirst + | element | + self isEmpty ifTrue: [ self error: 'Stack is empty' ]. + + element := elements at: topIndex. + elements at: topIndex put: nil. "Prevent memory leaks" + topIndex := topIndex - 1. + ^ element ] -{ #category : #operations } -CTStack >> push: anObject [ - "Adds a new object of any kind on top of the receiver." +{ #category : 'adding' } +CTStack >> push: anObject [ + + self isFull ifTrue: [ self error: 'Stack is full' ]. - elements addFirst: anObject. + topIndex := topIndex + 1. + elements at: topIndex put: anObject. ^ anObject ] -{ #category : #query } +{ #category : 'removing' } +CTStack >> removeAll [ + + 1 to: topIndex do: [ :i | elements at: i put: nil ]. + topIndex := 0 +] + +{ #category : 'accessing' } CTStack >> size [ - ^ elements size + ^ topIndex ] -{ #category : #operations } +{ #category : 'accessing' } CTStack >> top [ - "Returns the first element of the receiver without removing it." + + "Return the top element without removing it" - ^ elements first + self isEmpty ifTrue: [ self error: 'Stack is empty' ]. + ^ elements at: topIndex ] diff --git a/src/Containers-Stack/package.st b/src/Containers-Stack/package.st index c3d57aa..a21a418 100644 --- a/src/Containers-Stack/package.st +++ b/src/Containers-Stack/package.st @@ -1 +1 @@ -Package { #name : #'Containers-Stack' } +Package { #name : 'Containers-Stack' } From 5959c3c55af46ecda402e29f82ced6247d8e00f8 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Sun, 13 Jul 2025 08:38:49 +0530 Subject: [PATCH 2/3] Added conversion & iteration methods with tests --- .../CTStackTest.class.st | 134 ++++++++++++++++++ src/Containers-Stack/CTStack.class.st | 70 +++++++++ 2 files changed, 204 insertions(+) diff --git a/src/Containers-Stack-Tests/CTStackTest.class.st b/src/Containers-Stack-Tests/CTStackTest.class.st index cbd8d77..cae87d0 100644 --- a/src/Containers-Stack-Tests/CTStackTest.class.st +++ b/src/Containers-Stack-Tests/CTStackTest.class.st @@ -28,6 +28,28 @@ CTStackTest >> testAlternatingPushPop [ self assert: stack size equals: 2 ] +{ #category : 'tests' } +CTStackTest >> testAsArray [ + + | result | + stack push: 'first'; push: 'second'; push: 'third'. + result := stack asArray. + + self assert: result equals: #('third' 'second' 'first'). + "Elements from top to bottom" +] + +{ #category : 'tests' } +CTStackTest >> testAsOrderedCollection [ + + | result | + stack push: 'a'; push: 'b'; push: 'c'. + result := stack asOrderedCollection. + + self assert: result class equals: OrderedCollection. + self assert: result asArray equals: #('c' 'b' 'a'). +] + { #category : 'tests' } CTStackTest >> testAvailableSpace [ @@ -48,6 +70,29 @@ CTStackTest >> testCapacity [ self assert: stack capacity equals: 5. "Capacity doesn't change" ] +{ #category : 'tests' } +CTStackTest >> testCopyCreatesNewObject [ + + | copy | + stack + push: 'a'; + push: 'b'. + copy := stack copy. + self deny: stack identicalTo: copy +] + +{ #category : 'tests' } +CTStackTest >> testCopyHasSameContents [ + + | copy | + stack push: 'first'; push: 'second'; push: 'third'. + copy := stack copy. + + self assert: copy size equals: stack size. + self assert: copy top equals: stack top. + self assert: copy capacity equals: stack capacity +] + { #category : 'tests' } CTStackTest >> testDefaultStackCreation [ @@ -60,6 +105,18 @@ CTStackTest >> testDefaultStackCreation [ self assert: defaultStack availableSpace equals: 10 ] +{ #category : 'tests' } +CTStackTest >> testDoIteration [ + + | elements | + stack push: 'first'; push: 'second'; push: 'third'. + elements := OrderedCollection new. + + stack do: [ :each | elements add: each ]. + + self assert: elements asArray equals: #('third' 'second' 'first') +] + { #category : 'tests' } CTStackTest >> testIsEmpty [ @@ -80,6 +137,45 @@ CTStackTest >> testIsFull [ self deny: stack isFull ] +{ #category : 'tests' } +CTStackTest >> testLIFOOrdering [ + + stack push: 'first'; push: 'second'; push: 'third'; push: 'fourth'. + + self assert: stack pop equals: 'fourth'. + self assert: stack pop equals: 'third'. + self assert: stack pop equals: 'second'. + self assert: stack pop equals: 'first' +] + +{ #category : 'tests' } +CTStackTest >> testLargeCapacityStack [ + + | largeStack | + largeStack := CTStack new: 1000000. + + 1 to: 1000000 do: [ :i | largeStack push: i ]. + self assert: largeStack isFull. + self assert: largeStack top equals: 1000000. + + 1000000 to: 1 by: -1 do: [ :i | + self assert: largeStack pop equals: i + ]. + self assert: largeStack isEmpty +] + +{ #category : 'tests' } +CTStackTest >> testPopAllElements [ + + stack push: 'a'; push: 'b'; push: 'c'. + + stack pop; pop; pop. + + self assert: stack isEmpty. + self assert: stack size equals: 0. + self assert: stack availableSpace equals: 5 +] + { #category : 'tests' } CTStackTest >> testPopMultipleElements [ @@ -189,6 +285,44 @@ CTStackTest >> testPushToFullStack [ self should: [ stack push: 'overflow' ] raise: Error ] +{ #category : 'removing' } +CTStackTest >> testRemoveAll [ + + stack push: 'a'; push: 'b'; push: 'c'. + stack removeAll. + + self assert: stack isEmpty. + self assert: stack size equals: 0. + self assert: stack availableSpace equals: 5 +] + +{ #category : 'tests' } +CTStackTest >> testRemoveAllOnEmptyStack [ + + stack removeAll. + + self assert: stack isEmpty. + self assert: stack size equals: 0 +] + +{ #category : 'tests' } +CTStackTest >> testSearchExistingElement [ + + stack push: 'a'; push: 'b'; push: 'c'; push: 'b'. + + self assert: (stack search: 'b') equals: 1. "Top element" + self assert: (stack search: 'c') equals: 2. + self assert: (stack search: 'a') equals: 4. "Bottom element" +] + +{ #category : 'tests' } +CTStackTest >> testSearchNonExistentElement [ + + stack push: 'a'; push: 'b'; push: 'c'. + + self assert: (stack search: 'x') equals: -1 +] + { #category : 'tests' } CTStackTest >> testSize [ diff --git a/src/Containers-Stack/CTStack.class.st b/src/Containers-Stack/CTStack.class.st index 884de28..79669ca 100644 --- a/src/Containers-Stack/CTStack.class.st +++ b/src/Containers-Stack/CTStack.class.st @@ -34,6 +34,28 @@ CTStack class >> new: anInteger [ yourself ] +{ #category : 'converting' } +CTStack >> asArray [ + + | result | + self isEmpty ifTrue: [ ^ #() ]. + + result := Array new: self size. + 1 to: self size do: [ :i | + result at: i put: (elements at: topIndex - i + 1) + ]. + ^ result +] + +{ #category : 'converting' } +CTStack >> asOrderedCollection [ + + | result | + result := OrderedCollection new: self size. + self do: [ :each | result add: each ]. + ^ result +] + { #category : 'accessing' } CTStack >> availableSpace [ @@ -46,6 +68,30 @@ CTStack >> capacity [ ^ capacity ] +{ #category : 'copying' } +CTStack >> copy [ + + + | copy | + copy := self class new: capacity. + self isEmpty ifTrue: [ ^ copy ]. + + 1 to: topIndex do: [ :i | + copy push: (elements at: i) + ]. + ^ copy +] + +{ #category : 'enumerating' } +CTStack >> do: aBlock [ + + self isEmpty ifTrue: [ ^ self ]. + + topIndex to: 1 by: -1 do: [ :i | + aBlock value: (elements at: i) + ] +] + { #category : 'initialization' } CTStack >> initializeWithCapacity: anInteger [ @@ -92,6 +138,13 @@ CTStack >> push: anObject [ ^ anObject ] +{ #category : 'showing' } +CTStack >> pushAll: aCollection [ + + aCollection do: [ :each | self push: each ]. + ^ aCollection isEmpty ifFalse: [ aCollection last ] ifTrue: [ nil ] +] + { #category : 'removing' } CTStack >> removeAll [ @@ -99,6 +152,23 @@ CTStack >> removeAll [ topIndex := 0 ] +{ #category : 'accessing' } +CTStack >> search: anObject [ + + "Return the 1-based position of anObject from the top of the stack. + Return -1 if the object is not found. + The top element is at position 1." + + self isEmpty ifTrue: [ ^ -1 ]. + + topIndex to: 1 by: -1 do: [ :i | + (elements at: i) = anObject ifTrue: [ + ^ topIndex - i + 1 + ] + ]. + ^ -1 +] + { #category : 'accessing' } CTStack >> size [ From 79d33e50a089ae8b0b2d9f8fe662038907c92019 Mon Sep 17 00:00:00 2001 From: Alokzh Date: Sun, 13 Jul 2025 09:11:17 +0530 Subject: [PATCH 3/3] Improved workflows & enhanced Readme --- .github/workflows/CI.yml | 32 +++++++++++ .github/workflows/currentStablePharo.yml | 27 ---------- .github/workflows/matrix.yml | 36 ------------- README.md | 69 +++++++++++++++--------- 4 files changed, 77 insertions(+), 87 deletions(-) create mode 100644 .github/workflows/CI.yml delete mode 100644 .github/workflows/currentStablePharo.yml delete mode 100644 .github/workflows/matrix.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..eb20c59 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,32 @@ +name: CI + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + smalltalk: [Pharo64-13, Pharo64-12, Pharo64-11, Pharo64-10] + + runs-on: ${{ matrix.os }} + name: ${{ matrix.smalltalk }} on ${{ matrix.os }} + + steps: + - uses: actions/checkout@v3 + - name: Setup SmalltalkCI + uses: hpi-swa/setup-smalltalkCI@v1 + with: + smalltalk-version: ${{ matrix.smalltalk }} + - name: Load and Test + run: smalltalkci -s ${{ matrix.smalltalk }} + shell: bash + timeout-minutes: 15 \ No newline at end of file diff --git a/.github/workflows/currentStablePharo.yml b/.github/workflows/currentStablePharo.yml deleted file mode 100644 index bd6a7ae..0000000 --- a/.github/workflows/currentStablePharo.yml +++ /dev/null @@ -1,27 +0,0 @@ - -name: currentStablePharo - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -on: - push: - branches: - - master - workflow_dispatch: - -jobs: - build: - strategy: - matrix: - platform: [ubuntu-latest, macos-latest ] - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v2 - - uses: hpi-swa/setup-smalltalkCI@v1 - id: smalltalkci - with: - smalltalk-version: Pharo64-8.0 - - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} - shell: bash - timeout-minutes: 15 diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml deleted file mode 100644 index a847458..0000000 --- a/.github/workflows/matrix.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: matrix - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - strategy: - matrix: - os: [ macos-latest, windows-latest, ubuntu-latest] - smalltalk: [ Pharo64-8.0, Pharo64-7.0 ] - runs-on: ${{ matrix.os }} - name: ${{ matrix.smalltalk }} on ${{ matrix.os }} - steps: - - uses: actions/checkout@v2 - - name: Setup smalltalkCI - uses: hpi-swa/setup-smalltalkCI@v1 - with: - smalltalk-version: ${{ matrix.smalltalk }} - - name: Load Image and Run Tests - run: smalltalkci -s ${{ matrix.smalltalk }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - timeout-minutes: 15 - - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v1.1.2 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - flag-name: ${{matrix.os}}-${{matrix.smalltalk}} diff --git a/README.md b/README.md index 30b9017..39d1b21 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,19 @@ # Containers-Stack -A dead stupid stack implementation, but one fully working with super cool coverage:) - - -![https://github.com/pharo-containers/Containers-Stack/actions](https://github.com/pharo-containers/Containers-Stack/workflows/Matrix/badge.svg) -[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://img.shields.io/badge/license-MIT-blue.svg) -[![Coverage Status](https://coveralls.io/repos/github/pharo-containers/Containers-Stack/badge.svg?branch=master)](https://coveralls.io/github/pharo-containers/Containers-Stack?branch=master) -## Example - -``` -| aStack | - aStack := CTStack new. - aStack push: 'a'. - aStack size >>> 1. - aStack push: 'b'. - aStack size >>> 2. - aStack top >>> 'b'. - aStack size >>> 2. - aStack pop >>> 'b'. - aStack size >>> 1. - aStack pop >>> 'a'. - aStack size >>> 0. - ``` +A High-performance, Array based Stack implementation providing efficient LIFO (Last In, First Out) operations with fixed capacity and proper bounds checking. + +![Pharo Version](https://img.shields.io/badge/Pharo-10+-blue) +[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) + +## What is a Stack? + +A Stack is a linear data structure that follows the LIFO (Last In, First Out) principle. Elements are added and removed from the same end, called the "top" of the stack. Think of it like a stack of plates - you can only add or remove plates from the top. + +### Key Benefits +- **O(1) Performance**: Constant time push, pop, and top operations +- **Fixed Memory Usage**: Array-based implementation with bounded capacity +- **Memory Safe**: Automatic cleanup prevents memory leaks +- **Simple API**: Clean, intuitive interface following standard conventions +- **Robust Error Handling**: Proper stack overflow and underflow protection ## Loading The following script installs Containers-Stack in Pharo. @@ -28,7 +21,7 @@ The following script installs Containers-Stack in Pharo. ```smalltalk Metacello new baseline: 'ContainersStack'; - repository: 'github://pharo-containers/Containers-Stack:v1.0/src'; + repository: 'github://pharo-containers/Containers-Stack/src'; load. ``` @@ -39,5 +32,33 @@ Add the following code to your Metacello baseline or configuration ```smalltalk spec baseline: 'ContainersStack' - with: [ spec repository: 'github://pharo-containers/Containers-Stack:v1.0/src' ]. + with: [ spec repository: 'github://pharo-containers/Containers-Stack/src' ]. +``` + +## Quick Start + +```smalltalk +"Create a stack with capacity of 5" +stack := CTStack new: 5. + +"Push elements" +stack push: 'first'. +stack push: 'second'. +stack push: 'third'. + +"Check top element without removing" +stack top. "Returns 'third'" +stack size. "Returns 3" + +"Pop elements (LIFO order)" +stack pop. "Returns 'third'" +stack pop. "Returns 'second'" +stack pop. "Returns 'first'" + +"Stack is now empty" +stack isEmpty. "Returns true" ``` + +## Contributing + +This is part of the Pharo Containers project. Feel free to contribute by implementing additional methods, improving tests, or enhancing documentation. \ No newline at end of file