Compare commits

..

40 commits
dDogge ... main

Author SHA1 Message Date
dDogge
daa2dfc077 gitignore expanded 2024-12-11 15:57:57 +01:00
dDogge
69af73e315 lab 4 complete 2024-12-11 15:54:56 +01:00
Imbus
2769a3a0ad Prettier search, tests 2024-12-05 12:32:27 +01:00
Imbus
1dae994364 Bugfix 1 2024-12-05 12:02:17 +01:00
Imbus
6130bdee66 Format 2024-11-27 17:25:14 +01:00
Imbus
8abebb692a ignore 2024-11-27 17:15:16 +01:00
Imbus
4bb3629a76 Some assertions in tabletest 2024-11-27 17:14:47 +01:00
Imbus
cc34c03648 Makefile lab3 2024-11-27 17:14:34 +01:00
Imbus
c5e034c3ac Bugfix (assignment used over comparison) 2024-11-27 17:14:10 +01:00
Imbus
686fd07e08 Spelling 2024-11-21 13:34:17 +01:00
Imbus
abec11b35b Spell now behaves properly 2024-11-21 09:49:35 +01:00
Imbus
42f69296f6 Better distance sorting 2024-11-21 09:47:11 +01:00
Imbus
d4970c8d76 Include edit_distance in spell target 2024-11-21 09:46:54 +01:00
Imbus
57d5f34ee5 Better trim 2024-11-21 09:33:20 +01:00
Imbus
1c88d49452 Bugfix and ignore empty lines 2024-11-21 09:18:48 +01:00
Imbus
7a62bebf76 Initial implementation of matcher 2024-11-21 08:50:09 +01:00
Imbus
70170ea995 Formatting 2024-11-21 08:49:45 +01:00
Imbus
d10300509e Formatting 2024-11-21 08:47:51 +01:00
Imbus
7dd7f5610b Expose triagrams from word 2024-11-21 08:47:45 +01:00
Imbus
94d807fc67 Type casting fixes and bounding array access 2024-11-21 08:46:55 +01:00
Imbus
8c8930f5c5 Makefile targets for linting 2024-11-21 08:45:34 +01:00
Imbus
fe00d47e02 Ignore 2024-11-21 07:49:28 +01:00
Imbus
c6eb4cb6ae More picky compiler flags 2024-11-21 07:48:56 +01:00
Imbus
5b669caddb Contains 2024-11-21 07:48:49 +01:00
Imbus
b843fc98e0 Refactor 2024-11-21 07:48:45 +01:00
Imbus
fdae90ad9f bugfix 2024-11-20 19:11:48 +01:00
Imbus
744d0f7a3a Formatting makefile 2024-11-20 17:47:12 +01:00
Imbus
f9f3674fde Ignore 2024-11-20 17:46:44 +01:00
Imbus
7d93d5dbfa Lab2 ish 2024-11-20 17:46:21 +01:00
Imbus
e4e27d421a Gitignore 2024-11-12 04:57:57 +01:00
Imbus
3645b14f3c Clang-format 2024-11-12 04:57:54 +01:00
Imbus
dbd64f4545 Formatting 2024-11-12 04:57:48 +01:00
Imbus
53b9f8e4a3 Valgrind steps 2024-11-12 04:57:45 +01:00
Imbus
1f44b48fde Trailing space trim 2024-11-12 04:57:21 +01:00
Imbus
74ce672841 Significantly more stupid encoding than rot13 2024-11-12 03:05:51 +01:00
Imbus
63265d5cfb Bunch of ignores e.t.c. 2024-11-12 02:59:00 +01:00
Imbus
bdc3832fd1 Justfile for convenience 2024-11-11 18:06:14 +01:00
Imbus
b72f78839c Hello and editor 2024-11-11 18:06:07 +01:00
Imbus
43568e947f Ignore 2024-11-11 18:05:46 +01:00
Imbus
3f1ca7ecc1 Labs pdf 2024-11-06 17:56:11 +01:00
92 changed files with 1361 additions and 496 deletions

274
.clang-format Normal file
View file

@ -0,0 +1,274 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
...

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
*.o
*.d
*a.out*
build
.cache/
words.txt
compile_commands.json
lab2/edit
lab2/spell
lab3/tabletest
./vscode

2
Makefile Normal file
View file

@ -0,0 +1,2 @@
format:
find . -regex '.*\.\(c\|cpp\|cc\|cxx\|h\|hpp\|hh\|hxx\)' -exec clang-format {} +

BIN
cpplabs.pdf Normal file

Binary file not shown.

2
lab1/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
hello
test_editor

51
lab1/Justfile Normal file
View file

@ -0,0 +1,51 @@
all: a1 a2 a3 a4 cmake buggy
# Build the A1 lab exercise
a1:
g++ -o hello hello.cc
./hello
# Build the A2 lab exercise
a2:
g++ -std=c++11 -o separate_main separate_main.cc separate_fn.cc
# Build the A3 lab exercise
a3:
g++ -std=c++11 -c separate_main.cc
g++ -std=c++11 -c separate_fn.cc
g++ -std=c++11 -o separate_main separate_main.o separate_fn.o
# Build the A4 lab exercise
a4:
@echo "Will fail"
-g++ -std=c++11 -o separate_main separate_main.cc
# Build the A5 lab exercise
a5:
g++ -c -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast -std=c++11 hello.cc
# Build the cmake exercise
cmake:
rm -rf ./cmake-example/build # Start over
cd ./cmake-example && mkdir -p build
cd ./cmake-example/build && cmake ..
cd ./cmake-example/build && make -j$(nproc)
./cmake-example/build/SimpleMain
buggy:
cd ./buggy_programs && make -j4
cd ./buggy_programs && mkdir -p build
cd ./buggy_programs && cmake -B build
cd ./buggy_programs && make -C build
valgrind: buggy
cd ./buggy_programs/build/ && valgrind ./dangling
cd ./buggy_programs/build/ && valgrind ./bounds
cd ./buggy_programs/build/ && valgrind ./bounds-heap
cd ./buggy_programs/build/ && valgrind ./leak
cd ./buggy_programs/build/ && valgrind ./sum
cd ./buggy_programs/build/ && valgrind ./sum_alt
cd ./buggy_programs/build/ && valgrind ./ub
clean:
git clean -fdx

View file

@ -1,58 +1,17 @@
# Define the compiler and the linker. The linker must be defined since
# the implicit rule for linking uses CC as the linker. g++ can be
# changed to clang++.
CXX = g++
CC = $(CXX)
# Generate dependencies in *.d files
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
# -g is for debugging.
CPPFLAGS = -std=c++11 -I.
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
CXXFLAGS += -std=c++11
CXXFLAGS += -g
CXXFLAGS += $(DEPFLAGS)
LDFLAGS = -g
#CPPFLAGS += -stdlib=libc++
#CXXFLAGS += -stdlib=libc++
#LDFLAGS += -stdlib=libc++
# Targets
PROGS = test_editor test_coding print_argv hello encode decode
all: $(PROGS)
test: test_coding test_editor
./test_coding
./test_editor
./hello
test_encode_decode: encode decode
@echo "Running encode-decode tests"
./encode testfile.txt
./decode testfile.txt.enc
# Targets rely on implicit rules for compiling and linking
print_argv: print_argv.o
# The following rule means: "if test_editor does not exist, or
# is older than test_editor.o or editor.o,
# then link test_editor".
test_editor: test_editor.o editor.o
test_coding: test_coding.o coding.o
encode: encode.o coding.o
decode: decode.o coding.o
g++ -o test_editor test_editor.o editor.o
# Phony targets
.PHONY: all test test_encode_decode clean distclean
# Rules to create the object files.
test_editor.o: test_editor.cc editor.h
g++ -c test_editor.cc -std=c++11
editor.o: editor.cc editor.h
g++ -c editor.cc -std=c++11
# Standard clean
clean:
rm -f *.o $(PROGS)
print_argv: print_argv.o
g++ -o print_argv print_argv.o
print_argv.o: print_argv.cc
g++ -c print_argv.cc -std=c++11
distclean: clean
rm *.d
# Include the *.d files
SRC = $(wildcard *.cc)
-include $(SRC:.cc=.d)

View file

@ -1,17 +0,0 @@
# The following rule means: "if test_editor does not exist, or
# is older than test_editor.o or editor.o,
# then link test_editor".
test_editor: test_editor.o editor.o
g++ -o test_editor test_editor.o editor.o
# Rules to create the object files.
test_editor.o: test_editor.cc editor.h
g++ -c test_editor.cc -std=c++11
editor.o: editor.cc editor.h
g++ -c editor.cc -std=c++11
print_argv: print_argv.o
g++ -o print_argv print_argv.o
print_argv.o: print_argv.cc
g++ -c print_argv.cc -std=c++11

50
lab1/MakefileWithDeps Normal file
View file

@ -0,0 +1,50 @@
# Define the compiler and the linker. The linker must be defined since
# the implicit rule for linking uses CC as the linker. g++ can be
# changed to clang++.
CXX = g++
CC = $(CXX)
# Generate dependencies in *.d files
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
# -g is for debugging.
CPPFLAGS = -std=c++11 -I.
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
CXXFLAGS += -std=c++11
CXXFLAGS += -g
CXXFLAGS += $(DEPFLAGS)
LDFLAGS = -g
#CPPFLAGS += -stdlib=libc++
#CXXFLAGS += -stdlib=libc++
#LDFLAGS += -stdlib=libc++
# Targets
PROGS = test_editor test_coding print_argv
all: $(PROGS)
test: test_coding test_editor
./test_coding
./test_editor
# Targets rely on implicit rules for compiling and linking
print_argv: print_argv.o
test_editor: test_editor.o editor.o
test_coding: test_coding.o coding.o
# Phony targets
.PHONY: all test clean distclean
# Standard clean
clean:
rm -f *.o $(PROGS)
distclean: clean
rm *.d
# Include the *.d files
SRC = $(wildcard *.cc)
-include $(SRC:.cc=.d)

6
lab1/buggy_programs/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
bounds
bounds-heap
dangling
leak
sum
ub

View file

@ -21,30 +21,20 @@ PROGS=ub leak bounds bounds-heap dangling sum
ALL: $(PROGS)
leak: leak.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
dangling: dangling.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
bounds: bounds.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
ub: ub.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
sum: sum.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
# Targets
# Phony targets
.PHONY: all clean test
# Standard clean
clean:
-rm -f $(PROGS)
-rm -rf $(addsuffix .dSYM, $(PROGS))
test: $(PROGS)
@echo "Running tests with Valgrind..."
@for prog in $(PROGS); do \
echo "Testing $$prog with Valgrind:"; \
valgrind ./$$prog; \
echo ""; \
done
-rm $(PROGS)
-rm -r $(addsuffix .dSYM, $(PROGS))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
lab1/cmake-example/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build

View file

@ -1,10 +1,9 @@
#include<coding.h>
#include <coding.h>
unsigned char encode(unsigned char c)
{
return c + 2;
unsigned char encode(unsigned char c) {
return ++c;
}
unsigned char decode(unsigned char c)
{
return c - 2;
unsigned char decode(unsigned char c) {
return --c;
}

View file

@ -1,2 +0,0 @@
coding.o: coding.cc coding.h
coding.h:

Binary file not shown.

Binary file not shown.

View file

@ -1,34 +0,0 @@
#include <iostream>
#include <fstream>
#include "coding.h"
int main(int argc, char* argv[]) {
std::string filename;
if (argc > 1) {
filename = argv[1];
} else {
std::cout << "Enter filename to decode: ";
std::cin >> filename;
}
std::ifstream infile(filename, std::ios::binary);
if (!infile) {
std::cerr << "Could not open file " << filename << "\n";
return 1;
}
std::ofstream outfile(filename + ".dec", std::ios::binary);
if (!outfile) {
std::cerr << "Could not create output file" << "\n";
return 1;
}
unsigned char c;
while (infile.get(reinterpret_cast<char&>(c))) {
outfile.put(decode(c));
}
std::cout << "Decoding complete. Output saved to " << filename << ".dec" << "\n";
return 0;
}

View file

@ -1,2 +0,0 @@
decode.o: decode.cc coding.h
coding.h:

Binary file not shown.

View file

@ -6,29 +6,29 @@ using std::string;
using size_type = Editor::size_type;
size_type Editor::get_size() const
{
return text.size();
}
size_type Editor::get_size() const { return text.size(); }
size_type Editor::find_left_par(size_type pos) const {
if (pos >= text.size() || (text[pos] != ')' && text[pos] != ']' && text[pos] != '}')) {
return std::string::npos;
Editor::size_type Editor::find_left_par(size_type pos) const {
char right_par = text[pos];
char left_par;
// Determine the matching left parenthesis for the given right parenthesis
switch (right_par) {
case ')': left_par = '('; break;
case ']': left_par = '['; break;
case '}': left_par = '{'; break;
default: return string::npos; // Not a valid right parenthesis
}
char right_par = text[pos];
char left_par = (right_par == ')') ? '(' : (right_par == ']') ? '[' : '{';
int balance = 0;
for (int i = pos; i >= 0; --i) {
if (text[i] == right_par) {
balance++;
} else if (text[i] == left_par) {
int balance = 1; // Start with the right parenthesis at text[pos]
for (size_type i = pos; i-- > 0;) {
if (text[i] == left_par) {
balance--;
if (balance == 0) {
return i;
}
if (balance == 0) return i; // Found the matching left parenthesis
} else if (text[i] == right_par) {
balance++;
}
}
return string::npos; // No matching left parenthesis found
}

View file

@ -1,2 +0,0 @@
editor.o: editor.cc editor.h
editor.h:

View file

@ -4,24 +4,24 @@
#include <string>
class Editor {
public:
public:
using size_type = std::string::size_type;
/* Creates a text editor containing the text t */
Editor(const std::string& t) : text(t) {}
/* Creates a text editor containing the text t */
Editor(const std::string &t) : text(t) {}
/* Get the size of the current contents */
size_type get_size() const;
/*
* Text[pos] contains a right parentheses. Returns the position of
* the corresponding left parentheses, or string::npos if there
* is no match.
*/
size_type find_left_par(size_type pos) const;
/*
* Text[pos] contains a right parentheses. Returns the position of
* the corresponding left parentheses, or string::npos if there
* is no match.
*/
size_type find_left_par(size_type pos) const;
// ... functions to edit the text (insert and delete characters)
private:
std::string text;
// ... functions to edit the text (insert and delete characters)
private:
std::string text;
};
#endif

Binary file not shown.

Binary file not shown.

View file

@ -1,35 +0,0 @@
#include <iostream>
#include <fstream>
#include "coding.h"
int main (int argc, char* argv[]) {
std::string filename;
if (argc > 1) {
filename = argv[1];
} else {
std::cout << "Enter filename: ";
std::cin >> filename;
}
std::ifstream infile(filename, std::ios::binary);
if (!infile) {
std::cerr << "Could not open file " << filename << "\n";
return 1;
}
std::string output_filename = filename + ".enc";
std::ofstream outfile(output_filename, std::ios::binary);
if (!outfile) {
std::cerr << "Could not create output file" << "\n";
return 1;
}
unsigned char c;
while (infile.get(reinterpret_cast<char&>(c))) {
outfile.put(encode(c));
}
std::cout << "Encoding complete. Output saved to " << filename << "\n";
return 0;
}

View file

@ -1,2 +0,0 @@
encode.o: encode.cc coding.h
coding.h:

Binary file not shown.

Binary file not shown.

View file

@ -1,7 +1,5 @@
#include <iostream>
int main() {
std::cout << "Hello, World!" << "\n";
std::cout << "Hello, World!" << "\n";
return 0;
int main(int argc, char *argv[]) {
std::cout << "Hello" << std::endl;
}

View file

@ -1 +0,0 @@
hello: hello.cc

Binary file not shown.

View file

@ -1 +0,0 @@
print_argv.o: print_argv.cc

Binary file not shown.

View file

@ -1,49 +0,0 @@
1. What is the difference between a declaration and a definition?
A declaration tells the compiler about the existence of a variable or function,
while a definition allocates storage or provides the function code.
2. How does an include guard prevent multiple definitions?
An include guard (using #ifndef, #define, #endif)
prevents a header file from being included multiple times, which avoids redefinitions.
3. How can you tell if an error comes from the compiler or the linker? Does a linker error
mean that you have an error in your source code? How do you (typically) fix a linker error?
Compiler errors are syntax or semantic issues in code, while linker errors occur when symbols
are missing or duplicated across files. A linker error often means a missing definition or library; its fixed by ensuring all functions and variables are correctly defined and linked.
4. Do you have to make any changes to MakefileWithDeps to build your hello world program?
You may need to adjust MakefileWithDeps
if dependencies or file paths change for your hello world program.
5. In encode and decode, the type unsigned char is used. Would your code work the same
way if that type is changed to char or signed char?
Changing unsigned char to char or signed char
may alter the behavior due to differences in handling negative values.
6. In the coding problem, reading the file with char ch; while (infile >> ch) ... doesnt
work. Why?
infile >> ch reads formatted input, skipping whitespace;
using infile.get(ch) reads every character, including whitespace.
7. If your program crashes, how can you use the debugger to get a stack trace similar to that
of Exception.printStackTrace() in Java?
lldb ./progrma -> run -> bt
8. What is the difference between a debugger breakpoint and a watchpoint?
A breakpoint pauses execution at a specific line,
while a watchpoint stops execution when a specific variable changes.

View file

@ -25,8 +25,6 @@ PROGS = read-words example-out
all: $(PROGS)
test: ./example-out ./read-words
# Phony targets
.PHONY: all test clean distclean

View file

@ -1,2 +0,0 @@
And this is written to stderr
And some more to stderr

Binary file not shown.

View file

@ -1 +0,0 @@
example-out: example-out.cc

View file

@ -1,2 +0,0 @@
This text is written to stdout
More text to stdout

Binary file not shown.

View file

@ -1 +0,0 @@
read-words: read-words.cc

Binary file not shown.

View file

@ -1,2 +0,0 @@
test_coding.o: test_coding.cc coding.h
coding.h:

Binary file not shown.

Binary file not shown.

View file

@ -1,2 +0,0 @@
test_editor.o: test_editor.cc editor.h
editor.h:

Binary file not shown.

View file

@ -1 +0,0 @@
Hello my name is Douglas

View file

@ -1 +0,0 @@
Fcjjmkwl_kcgqBmsej_q

View file

@ -1 +0,0 @@
Jgnnq"o{"pcog"ku"Fqwincu

View file

@ -1 +0,0 @@
Hello my name is Douglas

37
lab2/Makefile Normal file
View file

@ -0,0 +1,37 @@
CXX = g++
CXXFLAGS = -Wall -Wextra -Wpedantic -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -std=c++17
#CXXFLAGS += -Werror
SRC = $(wildcard *.cc)
HDR = $(wildcard *.h)
OBJ = $(SRC:.cc=.o)
all: spell edit $(OBJ)
edit: test_edit_distance.o edit_distance.o
@echo "Building & linking $@"
@$(CXX) $(CXXFLAGS) $^ -o $@
spell: spell.o word.o dictionary.o edit_distance.o
@echo "Building & linking $@"
@$(CXX) $(CXXFLAGS) $^ -o $@
%.o:%.cc
@echo "Building $@"
@$(CXX) -c $(CXXFLAGS) $< -o $@
lint: clang-tidy cppcheck clang-format
clang-tidy:
clang-tidy $(SRC) -- $(CXXFLAGS)
cppcheck:
cppcheck --enable=all --language=c++ --std=c++17 --suppress=missingIncludeSystem -I/usr/include $(SRC) $(HDR)
clang-format:
clang-format -i $(SRC) $(HDR)
clean:
rm -f *.o spell edit
.PHONY: clean all lint clang-tidy cppcheck clang-format

View file

@ -1,22 +1,131 @@
#include <string>
#include <vector>
#include "dictionary.h"
#include "edit_distance.h"
#include "word.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <algorithm>
#include "word.h"
#include "dictionary.h"
#include <set>
#include <string>
#include <vector>
using std::string;
using std::vector;
Dictionary::Dictionary() {
Dictionary::Dictionary() {}
bool Dictionary::contains(const string &word) const {
auto l = word.length();
Word w = Word(word);
if (std::find(this->words[l].begin(), this->words[l].end(), w) !=
std::end(this->words[l])) {
return true;
}
return false;
}
bool Dictionary::contains(const string& word) const {
return true;
std::vector<string> Dictionary::get_suggestions(const string &word) const {
vector<string> suggestions;
add_trigram_suggestions(suggestions, word);
trim_suggestions(suggestions, word);
rank_suggestions(suggestions, word);
return suggestions;
}
vector<string> Dictionary::get_suggestions(const string& word) const {
vector<string> suggestions;
return suggestions;
void Dictionary::add_trigram_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const {
// Get trigrams of the input word
Word input_word(word);
const std::vector<std::string> &input_trigrams = input_word.get_trigrams();
// Iterate through all words in the dictionary
for (int i = 0; i < MAXLEN; ++i) {
for (const Word &dict_word : words[i]) {
// Get the trigrams of the dictionary word
const std::vector<std::string> &dict_word_trigrams =
dict_word.get_trigrams();
// Count how many trigrams match
unsigned int match_count = dict_word.get_matches(input_trigrams);
// If there are any matches, add the word to suggestions
if (match_count > 0) {
suggestions.push_back(dict_word.get_word());
}
}
}
}
void Dictionary::rank_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const {
// Sort suggestions based on the levenshtein distance
std::sort(suggestions.begin(), suggestions.end(),
[&](const std::string &a, const std::string &b) {
auto dist_a = edit_distance(a, word);
auto dist_b = edit_distance(b, word);
return dist_a < dist_b;
});
}
void Dictionary::trim_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const {
// Remove duplicates using a set
std::set<std::string> unique_suggestions(suggestions.begin(),
suggestions.end());
suggestions.assign(unique_suggestions.begin(), unique_suggestions.end());
// Remove the input word from the suggestions list (if present)
suggestions.erase(std::remove(suggestions.begin(), suggestions.end(), word),
suggestions.end());
auto l = word.length();
std::cout << "WTF" << l << std::endl;
// Example: Remove any suggestions that are not within 1 string length
suggestions.erase(std::remove_if(suggestions.begin(), suggestions.end(),
[l](const std::string &s) {
return s.length() > (l + 1) ||
s.length() < (l - 1);
}),
suggestions.end());
}
int Dictionary::spit(path p) {
std::ofstream file(p);
if (!file.is_open()) {
std::cerr << "Error opening file! " << std::endl;
return 1;
}
for (int a = 0; a < MAXLEN; a++) {
for (auto &word : words[a]) {
file << word;
file << std::endl;
}
}
file.flush();
file.close();
return 0;
}
int Dictionary::slurp(path p) {
std::ifstream file(p.string());
if (!file.is_open()) {
std::cerr << "Error opening file! " << std::endl;
return 1;
}
std::string line;
while (std::getline(file, line)) {
if (line.empty())
continue;
// Words larger than max gets placed in the topmost bucket
words[std::min(line.size(), static_cast<size_t>(MAXLEN) - 1)].push_back(
Word(line));
}
file.close();
return 0;
}

View file

@ -1,15 +1,29 @@
#ifndef DICTIONARY_H
#define DICTIONARY_H
#pragma once
#include "word.h"
#include <filesystem>
#include <string>
#include <vector>
class Dictionary {
public:
Dictionary();
bool contains(const std::string& word) const;
std::vector<std::string> get_suggestions(const std::string& word) const;
private:
};
#define MAXLEN 30
#endif
// using std::vector;
using std::filesystem::path;
class Dictionary {
public:
Dictionary();
void add_trigram_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const;
void rank_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const;
void trim_suggestions(std::vector<std::string> &suggestions,
const std::string &word) const;
bool contains(const std::string &word) const;
std::vector<std::string> get_suggestions(const std::string &word) const;
int slurp(path p);
int spit(path p);
private:
std::vector<Word> words[MAXLEN];
};

35
lab2/edit_distance.cc Normal file
View file

@ -0,0 +1,35 @@
#include <algorithm>
#include <string>
#include <vector>
int edit_distance(const std::string &s1, const std::string &s2) {
size_t m = s1.size();
size_t n = s2.size();
// Create a 2D DP table
std::vector<std::vector<size_t>> dp(m + 1, std::vector<size_t>(n + 1));
// Fill the base cases
for (size_t i = 0; i <= m; ++i)
dp[i][0] = i; // Deletion cost
for (size_t j = 0; j <= n; ++j)
dp[0][j] = j; // Insertion cost
// Fill the DP table
for (size_t i = 1; i <= m; ++i) {
for (size_t j = 1; j <= n; ++j) {
if (s1[i - 1] == s2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1]; // No operation needed
} else {
dp[i][j] = 1 + std::min({
dp[i - 1][j], // Deletion
dp[i][j - 1], // Insertion
dp[i - 1][j - 1] // Substitution
});
}
}
}
return static_cast<int>(dp[m][n]);
}

17
lab2/edit_distance.h Normal file
View file

@ -0,0 +1,17 @@
#include <string>
/**
* @brief Computes the edit distance (Levenshtein distance) between two strings.
*
* The edit distance is defined as the minimum number of single-character edits
* (insertions, deletions, or substitutions) required to transform one string
* into the other.
*
* This implementation uses dynamic programming to compute the distance
* efficiently.
*
* @param s1 The first string.
* @param s2 The second string.
* @return The edit distance between the two strings.
*/
int edit_distance(const std::string &s1, const std::string &s2);

View file

@ -1,18 +1,18 @@
#include "dictionary.h"
#include <algorithm>
#include <cctype>
#include <filesystem>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cctype>
#include "dictionary.h"
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
void check_word(const string& word, const Dictionary& dict)
{
void check_word(const string &word, const Dictionary &dict) {
if (dict.contains(word)) {
cout << "Correct." << endl;
} else {
@ -21,18 +21,22 @@ void check_word(const string& word, const Dictionary& dict)
cout << "Wrong, no suggestions." << endl;
} else {
cout << "Wrong. Suggestions:" << endl;
for (const auto& w : suggestions) {
for (const auto &w : suggestions) {
cout << " " << w << endl;
}
}
}
}
int main() {
Dictionary dict;
string word;
while (cin >> word) {
transform(word.begin(), word.end(), word.begin(), ::tolower);
Dictionary dict;
string word;
dict.slurp(std::filesystem::path("/usr/share/dict/words"));
// dict.spit(std::filesystem::path("words.txt"));
while (cin >> word) {
std::transform(word.begin(), word.end(), word.begin(), ::tolower);
check_word(word, dict);
}
}
return 0;
}

View file

@ -8,8 +8,7 @@
#include <iostream>
bool do_test(const std::string& x, const std::string& y, int expected)
{
bool do_test(const std::string &x, const std::string &y, int expected) {
auto actual = edit_distance(x, y);
if (actual != expected) {
std::cout << "*** WRONG: distance(" << x << ", " << y << ") was "
@ -19,8 +18,7 @@ bool do_test(const std::string& x, const std::string& y, int expected)
return false;
}
int main()
{
int main() {
int res = do_test("foobar", "foobar", 0);
res += do_test("x", "x", 0);
res += do_test("baz", "bar", 1);

View file

@ -1,16 +1,63 @@
#include "word.h"
#include "dictionary.h"
#include <algorithm>
#include <string>
#include <vector>
#include "word.h"
using std::vector;
using std::string;
using std::vector;
Word::Word(const string& w, const vector<string>& t) {}
string Word::get_word() const {
return string();
Word::Word(const string &w, const vector<string> &t) : word(w), trigrams(t) {
std::sort(trigrams.begin(), trigrams.end());
}
unsigned int Word::get_matches(const vector<string>& t) const {
return 0;
std::vector<std::string> get_trigrams(const std::string &text) {
std::vector<std::string> trigrams;
if (text.size() < 3) {
return trigrams; // Return an empty vector if the input is too short
}
for (size_t i = 0; i <= text.size() - 3; ++i) {
trigrams.push_back(
text.substr(i, 3)); // Extract a substring of length 3
}
return trigrams;
}
Word::Word(const std::string &w) : word(w) {
this->trigrams = ::get_trigrams(w);
std::sort(trigrams.begin(), trigrams.end());
}
string Word::get_word() const { return word; }
vector<std::string> Word::get_trigrams() const { return trigrams; }
unsigned int Word::get_matches(const vector<string> &t) const {
unsigned int matches = 0;
for (const auto &trigram : t) {
if (std::binary_search(trigrams.begin(), trigrams.end(), trigram)) {
++matches;
}
}
return matches;
}
std::ostream &operator<<(std::ostream &out, const Word &w) {
auto space = string(" ");
out << w.word;
out << space;
out << w.trigrams.size();
for (const auto &tri : w.trigrams) {
out << space << tri;
}
return out;
}
bool operator==(const Word &lhs, const Word &rhs) {
return lhs.word == rhs.word &&
std::equal(lhs.trigrams.begin(), lhs.trigrams.end(),
rhs.trigrams.begin());
}

View file

@ -1,21 +1,34 @@
#ifndef WORD_H
#define WORD_H
#pragma once
#include <string>
#include <vector>
/*
* Contains a word and its trigrams
*/
class Word {
public:
/* Creates a word w with the sorted trigrams t */
Word(const std::string& w, const std::vector<std::string>& t);
public:
/** Creates a word w with the sorted trigrams t */
Word(const std::string &w, const std::vector<std::string> &t);
/* Returns the word */
std::string get_word() const;
/** Creates a word w and derives the trigrams internally */
Word(const std::string &w);
/* Returns how many of the trigrams in t that are present
in this word's trigram vector */
unsigned int get_matches(const std::vector<std::string>& t) const;
private:
/** Returns the word */
std::string get_word() const;
/** Returns trigrams */
std::vector<std::string> get_trigrams() const;
/** Returns how many of the trigrams in t that are present
in this word's trigram vector */
unsigned int get_matches(const std::vector<std::string> &t) const;
private:
const std::string word;
std::vector<std::string> trigrams;
friend std::ostream &operator<<(std::ostream &out, const Word &o);
friend bool operator==(const Word &lhs, const Word &rhs);
};
#endif
bool operator==(const Word &lhs, const Word &rhs);

33
lab3/Makefile Normal file
View file

@ -0,0 +1,33 @@
CXX = g++
CXXFLAGS = -Wall -Wextra -Wpedantic -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -std=c++17
#CXXFLAGS += -Werror
SRC = $(wildcard *.cc)
HDR = $(wildcard *.h)
OBJ = $(SRC:.cc=.o)
all: tabletest $(OBJ)
tabletest: $(OBJ)
@echo "Building & linking $@"
@$(CXX) $(CXXFLAGS) $^ -o $@
%.o:%.cc
@echo "Building $@"
@$(CXX) -c $(CXXFLAGS) $< -o $@
lint: clang-tidy cppcheck clang-format
clang-tidy:
clang-tidy $(SRC) -- $(CXXFLAGS)
cppcheck:
cppcheck --enable=all --language=c++ --std=c++17 --suppress=missingIncludeSystem -I/usr/include $(SRC) $(HDR)
clang-format:
clang-format -i $(SRC) $(HDR)
clean:
rm -f *.o spell edit
.PHONY: clean all lint clang-tidy cppcheck clang-format

View file

@ -1,6 +1,5 @@
#include "User.h"
std::ostream& operator<<(std::ostream& os, const User& u)
{
return os << "(" << u.getCardNbr() << ") "<< u.getName();
std::ostream &operator<<(std::ostream &os, const User &u) {
return os << "(" << u.getCardNbr() << ") " << u.getName();
}

View file

@ -8,20 +8,26 @@ using std::cout;
using std::endl;
class User {
public:
User() :cardNbr{0},name{"default"}{}
User(int c, std::string n) :cardNbr{c},name{n} {}
~User() {cardNbr=-2; name="--------------------";} // overwrite values for security reasons
User(const User& u) =default;
User& operator=(const User&) =default;
int getCardNbr() const {return cardNbr;}
std::string getName() const {return name;}
bool operator==(const User& u) const {return cardNbr == u.cardNbr && name == u.name;}
bool operator!=(const User& u) const {return ! (u == *this);}
private:
public:
User() : cardNbr{0}, name{"default"} {}
User(int c, std::string n) : cardNbr{c}, name{n} {}
~User() {
cardNbr = -2;
name = "--------------------";
} // overwrite values for security reasons
User(const User &u) = default;
User &operator=(const User &) = default;
int getCardNbr() const { return cardNbr; }
std::string getName() const { return name; }
bool operator==(const User &u) const {
return cardNbr == u.cardNbr && name == u.name;
}
bool operator!=(const User &u) const { return !(u == *this); }
private:
int cardNbr;
std::string name;
};
std::ostream& operator<<(std::ostream& os, const User& u);
std::ostream &operator<<(std::ostream &os, const User &u);
#endif

View file

@ -1,24 +1,22 @@
#include "UserTable.h"
#include <fstream>
#include <algorithm>
#include <fstream>
const User UserTable::user_not_found = User{-1,"Not Found"};
const User UserTable::user_not_found = User{-1, "Not Found"};
UserTable::UserTable() :users{new User[capacity]} { }
UserTable::UserTable() : users{new User[capacity]} {}
UserTable::UserTable(const std::string& fname) :UserTable{}
{
UserTable::UserTable(const std::string &fname) : UserTable{} {
std::ifstream ufile(fname);
if(ufile.is_open()) {
while(ufile) {
if (ufile.is_open()) {
while (ufile) {
int cn;
if(ufile >> cn ) {
if (ufile >> cn) {
ufile.ignore(); // skip space
char n[80];
ufile.getline(n,80);
addUser(User(cn,n));
ufile.getline(n, 80);
addUser(User(cn, n));
}
}
} else {
@ -26,38 +24,39 @@ UserTable::UserTable(const std::string& fname) :UserTable{}
}
}
void UserTable::addUser(const User& u)
{
void UserTable::addUser(const User &u) {
// gör tabellen större vid behov
ensureCapacity(n+1);
ensureCapacity(n + 1);
// 1. Hitta rätt plats
int pos{0};
while ( (pos < n) && (users[pos].getCardNbr() < u.getCardNbr())){
while ((pos < n) && (users[pos].getCardNbr() < u.getCardNbr())) {
++pos;
}
//2. skapa lucka i vektorn
for(int i=n; i > pos; --i){
users[i] = users[i-1];
// 2. skapa lucka i vektorn
for (int i = n; i > pos; --i) {
users[i] = users[i - 1];
}
//3. stoppa in den nya användaren i luckan
// 3. stoppa in den nya användaren i luckan
users[pos] = u;
++n;
}
User UserTable::find(int c) const
{
User UserTable::find(int c) const {
// binärsökning (baserad på Holm, 2007)
int low = 0;
int high = n - 1;
int mid = -1;
bool found = false;
while (low < high && ! found) {
while (low < high && !found) {
mid = (low + high) / 2;
//
int midnbr = users[mid].getCardNbr();
if (midnbr = c) {
const int midnbr = users[mid].getCardNbr();
if (c == midnbr) {
found = true;
} else if (users[mid].getCardNbr() < c) {
low = mid + 1;
@ -68,48 +67,41 @@ User UserTable::find(int c) const
return found ? users[mid] : user_not_found;
}
User UserTable::find(std::string name) const
{
for (int i = 0; i != n; ++i) {
if (users[i].getName() == name) {
return users[i];
} else {
return user_not_found;
}
}
return user_not_found;
User UserTable::find(std::string name) const {
auto it = std::find_if(users, users + n, [&name](const User &u) {
return u.getName() == name;
});
// If it is at the 'end' of users, the result is not found
return (it != users+n) ? *it : user_not_found;
}
void UserTable::ensureCapacity(int s)
{
if(s>capacity) {
while(s > capacity) {
capacity*=4;
void UserTable::ensureCapacity(int s) {
if (s > capacity) {
while (s > capacity) {
capacity *= 4;
}
auto tmp = new User[capacity];
std::copy(users, users+n, tmp);
std::copy(users, users + n, tmp);
delete[] users;
users=tmp;
users = tmp;
}
}
void UserTable::print(std::ostream& os) const
{
void UserTable::print(std::ostream &os) const {
os << "-------------" << std::endl;
for(int i = 0; i != getNbrUsers(); ++i) {
const auto& u = users[i];
os << "(" <<u.getCardNbr() << ") " << u.getName() << std::endl;
for (int i = 0; i != getNbrUsers(); ++i) {
const auto &u = users[i];
os << "(" << u.getCardNbr() << ") " << u.getName() << std::endl;
}
os << "=============" << std::endl;
}
/**
* Testmetod för binärsökningen:
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
* alla sökningar lyckades, returneras 0.
*/
int testFindNbr(const UserTable ut)
{
* Testmetod för binärsökningen:
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
* alla sökningar lyckades, returneras 0.
*/
int testFindNbr(const UserTable ut) {
for (int i = 0; i < ut.n; i++) {
int nbr = ut.users[i].getCardNbr();
User found = ut.find(nbr);
@ -119,4 +111,3 @@ int testFindNbr(const UserTable ut)
}
return 0;
}

View file

@ -5,28 +5,27 @@
#include "User.h"
class UserTable{
public:
class UserTable {
public:
UserTable();
UserTable(const std::string&);
~UserTable() {delete[] users;}
UserTable(const std::string &);
~UserTable() { delete[] users; }
void addUser(const User&);
void addUser(const User &);
User find(int) const;
User find(std::string) const;
int getNbrUsers() const {
return n;
}
int getNbrUsers() const { return n; }
void print(std::ostream&) const;
void print(std::ostream &) const;
static const User user_not_found;
private:
private:
int capacity{1000};
void ensureCapacity(int);
int n{0};
User* users;
User *users;
friend int testFindNbr(const UserTable ut);
};

42
lab3/UserTableTest.cc Normal file
View file

@ -0,0 +1,42 @@
#include "UserTable.h"
#include "User.h"
#include <cassert>
int main() {
{ /* User Related Tests */
// Two identical users
User u1 = User(1234, "Name Nameson");
User u2 = User(1234, "Name Nameson");
assert(u1.getName() == u2.getName());
assert(u1.getCardNbr() == u2.getCardNbr());
// Two different users
User u3 = User(1200, "Name Surname");
User u4 = User(1201, "Name Nameson");
assert(u3.getName() != u4.getName());
assert(u3.getCardNbr() != u4.getCardNbr());
}
{ /* Table Related Tests */
UserTable tbl1 = UserTable();
assert(tbl1.find("Jens Holmgren") == UserTable::user_not_found);
tbl1.addUser(User(1200, "Table Yes"));
assert(tbl1.getNbrUsers() == 1);
}
{
// Assumes 'users.txt' is present, containing
// line separated records formatted as:
// "89524 Adam Abrahamsson"
UserTable tbl = UserTable("users.txt");
assert(tbl.getNbrUsers() > 0);
assert(tbl.find("Jens Holmgren") != UserTable::user_not_found);
tbl.addUser(User(1200, "Name Surname"));
User ufind1 = tbl.find(1200);
assert(ufind1 != UserTable::user_not_found);
User ufind2 = tbl.find("Name Surname");
assert(ufind2 != UserTable::user_not_found);
}
}

View file

@ -4,6 +4,7 @@
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"clocale": "cpp",
@ -31,13 +32,13 @@
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"regex": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",

74
lab4/Sieve.cc Normal file
View file

@ -0,0 +1,74 @@
#include <iostream>
#include <string>
#include <vector>
class Sieve {
private:
std::string sieve;
public:
// Constructor to initialize sieve with 'P' (prime assumption)
Sieve(size_t limit) : sieve(limit + 1, 'P') {
// 0 and 1 are not primes
sieve[0] = 'C';
if (limit > 0) sieve[1] = 'C';
// Sieve of Eratosthenes
for (size_t i = 2; i * i <= limit; ++i) {
if (sieve[i] == 'P') {
for (size_t j = i * i; j <= limit; j += i) {
sieve[j] = 'C';
}
}
}
}
// Get primes as a vector of integers
std::vector<int> getPrimes() const {
std::vector<int> primes;
for (size_t i = 2; i < sieve.size(); ++i) {
if (sieve[i] == 'P') {
primes.push_back(i);
}
}
return primes;
}
// Print all primes in the range
void printPrimesInRange(int start, int end) const {
for (int i = start; i <= end; ++i) {
if (sieve[i] == 'P') {
std::cout << i << " ";
}
}
std::cout << std::endl;
}
// Get the largest prime below a limit
int largestPrimeBelow(int limit) const {
for (int i = limit; i >= 2; --i) {
if (sieve[i] == 'P') {
return i;
}
}
return -1; // If no prime is found
}
};
// Main function for testing
int main() {
const int limit = 100000;
// Create a Sieve instance for the range 0 to limit
Sieve sieve(limit);
// Print primes between 1 and 200
std::cout << "Primes between 1 and 200:" << std::endl;
sieve.printPrimesInRange(1, 200);
// Find and print the largest prime below 100,000
int largestPrime = sieve.largestPrimeBelow(limit);
std::cout << "Largest prime below " << limit << ": " << largestPrime << std::endl;
return 0;
}

32
lab4/TagRemover.cc Normal file
View file

@ -0,0 +1,32 @@
#include <iostream>
#include <regex>
#include <string>
class TagRemover {
private:
std::string content;
public:
TagRemover(std::istream& input) {
std::string line;
while (std::getline(input, line)) {
content += line + '\n';
}
}
void print(std::ostream& output) const {
std::string result = std::regex_replace(content, std::regex("<[^>]*>"), "");
result = std::regex_replace(result, std::regex("&lt;"), "<");
result = std::regex_replace(result, std::regex("&gt;"), ">");
result = std::regex_replace(result, std::regex("&nbsp;"), " ");
result = std::regex_replace(result, std::regex("&amp;"), "&");
output << result;
}
};
int main() {
TagRemover tr(std::cin);
tr.print(std::cout);
return 0;
}

View file

@ -1,30 +1,86 @@
#include <ctime> // time and localtime
#include <ctime> // för tid och localtime
#include <iomanip> // för setw och setfill
#include <sstream> // för inputhantering
#include "date.h"
int Date::daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// Konstruktor: dagens datum
Date::Date() {
time_t timer = time(0); // time in seconds since 1970-01-01
tm* locTime = localtime(&timer); // broken-down time
year = 1900 + locTime->tm_year;
month = 1 + locTime->tm_mon;
day = locTime->tm_mday;
time_t timer = time(0); // tid i sekunder sedan 1970-01-01
tm* locTime = localtime(&timer); // lokal tid
year = 1900 + locTime->tm_year;
month = 1 + locTime->tm_mon;
day = locTime->tm_mday;
}
Date::Date(int y, int m, int d) {}
// Konstruktor: specifikt datum
Date::Date(int y, int m, int d) : year(y), month(m), day(d) {}
// Get-funktioner
int Date::getYear() const {
return 0;
return year;
}
int Date::getMonth() const {
return 0;
return month;
}
int Date::getDay() const {
return 0;
return day;
}
// Gå till nästa dag
void Date::next() {
day++;
if (day > daysPerMonth[month - 1] + (month == 2 && isLeapYear(year))) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
}
// Kontrollera om ett år är ett skottår
bool Date::isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
// Overloaded operator<< (output)
std::ostream& operator<<(std::ostream& os, const Date& date) {
os << std::setw(4) << std::setfill('0') << date.getYear() << '-'
<< std::setw(2) << std::setfill('0') << date.getMonth() << '-'
<< std::setw(2) << std::setfill('0') << date.getDay();
return os;
}
// Overloaded operator>> (input)
std::istream& operator>>(std::istream& is, Date& date) {
std::string input;
is >> input;
std::istringstream iss(input);
char dash1, dash2;
int y, m, d;
if (iss >> y >> dash1 >> m >> dash2 >> d && dash1 == '-' && dash2 == '-') {
// Validera månad och dag
if (m >= 1 && m <= 12) {
int maxDay = Date::daysPerMonth[m - 1];
if (m == 2 && Date::isLeapYear(y)) {
maxDay = 29; // Februari har 29 dagar under skottår
}
if (d >= 1 && d <= maxDay) {
date = Date(y, m, d); // Sätt datumet om det är giltigt
return is;
}
}
}
// Ogiltig inmatning
is.setstate(std::ios_base::failbit);
return is;
}

View file

@ -1,19 +1,27 @@
#ifndef DATE_H
#define DATE_H
#include <iostream>
class Date {
public:
Date(); // today's date
Date(int y, int m, int d); // yyyy-mm-dd
int getYear() const; // get the year
int getMonth() const; // get the month
int getDay() const; // get the day
void next(); // advance to next day
Date(); // dagens datum
Date(int y, int m, int d); // yyyy-mm-dd
int getYear() const; // returnerar året
int getMonth() const; // returnerar månaden
int getDay() const; // returnerar dagen
void next(); // går till nästa dag
// Overloaded operators
friend std::ostream& operator<<(std::ostream& os, const Date& date);
friend std::istream& operator>>(std::istream& is, Date& date);
private:
int year; // the year (four digits)
int month; // the month (1-12)
int day; // the day (1-..)
static int daysPerMonth[12]; // number of days in each month
int year; // året (fyra siffror)
int month; // månaden (1-12)
int day; // dagen (1-...)
static int daysPerMonth[12]; // antal dagar i varje månad
static bool isLeapYear(int year); // kontrollera skottår
};
#endif

View file

@ -1,64 +1,40 @@
#include <iostream>
#include <iomanip> // for setw and setfill
#include "date.h"
using std::cout;
using std::endl;
using std::setw;
using std::setfill;
/*
* Prints the date d in the format yyyy-mm-dd. You shall replace this
* function with an overloaded operator<<, and add an overloaded operator>>.
*
*/
void print(const Date& d) {
cout << setw(4) << setfill('0') << d.getYear() << '-';
cout << setw(2) << setfill('0') << d.getMonth() << '-';
cout << setw(2) << setfill('0') << d.getDay();
}
int main() {
// Check input and output of dates. Uncomment the following when you
// have added operator>> and operator<<.
/*
bool cont = true;
while (cont) {
cout << "Type a date: ";
Date aDate;
cin >> aDate;
if (cin.eof()) {
cont = false;
} else if (!cin.good()) {
cout << "Wrong input format" << endl;
// restore stream state and ignore the rest of the line
cin.clear();
cin.ignore(10000, '\n');
}
else {
cout << "Output: " << aDate << endl;
}
}
*/
// Test input och output
bool cont = true;
while (cont) {
std::cout << "Type a date: ";
Date aDate;
std::cin >> aDate;
// Check 'next' by creating an object describing today's date, then
// printing dates more than a month ahead
cout << "--- Today and more than a month ahead:" << endl;
Date d1;
print(d1);
cout << endl;
for (int i = 1; i <= 35 ; ++i) {
d1.next();
print(d1);
cout << endl;
}
if (std::cin.eof()) {
cont = false;
} else if (!std::cin.good()) {
std::cout << "Wrong input format" << std::endl;
std::cin.clear();
std::cin.ignore(10000, '\n');
} else {
std::cout << "Output: " << aDate << std::endl;
}
}
// Check so 'next' functions correctly from one year to the next
cout << "--- New Year's Eve and the next day:" << endl;
Date d2(2013, 12, 31);
print(d2);
cout << endl;
d2.next();
print(d2);
cout << endl;
// Testa 'next' med dagens datum
std::cout << "--- Today and more than a month ahead:" << std::endl;
Date d1;
std::cout << d1 << std::endl;
for (int i = 1; i <= 35; ++i) {
d1.next();
std::cout << d1 << std::endl;
}
// Testa 'next' från nyårsafton
std::cout << "--- New Year's Eve and the next day:" << std::endl;
Date d2(2013, 12, 31);
std::cout << d2 << std::endl;
d2.next();
std::cout << d2 << std::endl;
return 0;
}

56
lab4/makefile Normal file
View file

@ -0,0 +1,56 @@
# Compiler
CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic
# Targets
TARGETS = TagRemover Sieve date_test toString_test string_cast_test
# Source files
SRCS_TAGREMOVER = TagRemover.cc
SRCS_SIEVE = Sieve.cc
SRCS_DATE = date.cc
SRCS_DATE_TEST = date_test.cc
SRCS_TOSTRING_TEST = toString_test.cc date.cc
SRCS_STRING_CAST_TEST = string_cast_test.cc date.cc
# Object files
OBJS_TAGREMOVER = $(SRCS_TAGREMOVER:.cc=.o)
OBJS_SIEVE = $(SRCS_SIEVE:.cc=.o)
OBJS_DATE = $(SRCS_DATE:.cc=.o)
OBJS_DATE_TEST = $(SRCS_DATE_TEST:.cc=.o)
OBJS_TOSTRING_TEST = $(SRCS_TOSTRING_TEST:.cc=.o)
OBJS_STRING_CAST_TEST = $(SRCS_STRING_CAST_TEST:.cc=.o)
# Default target
all: $(TARGETS)
# Rule to build TagRemover
TagRemover: $(OBJS_TAGREMOVER)
$(CXX) $(CXXFLAGS) -o $@ $^
# Rule to build Sieve
Sieve: $(OBJS_SIEVE)
$(CXX) $(CXXFLAGS) -o $@ $^
# Rule to build date_test
date_test: $(OBJS_DATE_TEST) $(OBJS_DATE)
$(CXX) $(CXXFLAGS) -o $@ $^
# Rule to build toString_test
toString_test: $(OBJS_TOSTRING_TEST)
$(CXX) $(CXXFLAGS) -o $@ $^
# Rule to build string_cast_test
string_cast_test: $(OBJS_STRING_CAST_TEST)
$(CXX) $(CXXFLAGS) -o $@ $^
# Rule to compile source files into object files
%.o: %.cc
$(CXX) $(CXXFLAGS) -c $<
# Clean up build artifacts
clean:
rm -f $(OBJS_TAGREMOVER) $(OBJS_SIEVE) $(OBJS_DATE) $(OBJS_DATE_TEST) $(OBJS_TOSTRING_TEST) $(OBJS_STRING_CAST_TEST) $(TARGETS)
# Phony targets
.PHONY: all clean

61
lab4/reflektion.txt Normal file
View file

@ -0,0 +1,61 @@
1. In your tests, how did you test the error handling (e.g., that a wrong string_cast actually
throws?)
Genom att använda en ogiltig inmatning, som "abc" eller "123abc", och verifiera att std::invalid_argument kastas korrekt.
2. In TagRemover, why do you think the constructor takes an istream instead of just the
filename?
Det gör klassen mer flexibel eftersom den kan arbeta med vilken ström som helst, inte bara filer. Till exempel kan den användas med std::cin eller std::stringstream.
3. In TagRemover, did you process the file line by line, or did you first read the entire file?
What are the pros and cons of these two approaches?
Jag läste hela filen först eftersom det är enklare att använda regex för att bearbeta hela texten på en gång.
Fördelen är att det är mer effektivt för regex-matchning, men nackdelen är att det kräver mer minne för stora filer.
4. How do you read the entire contents of an std::istream into a std::string without using
a for or while loop?
Genom att använda:
std::string content((std::istreambuf_iterator<char>(istream)), std::istreambuf_iterator<char>());
5. In TagRemover, do you have duplicate code for translating the special characters? If so, how
would you refactor your code to avoid duplicate code?
Ja, det finns duplicerad kod för varje specialtecken. Jag skulle använda en std::map för att lagra mönster och ersättningar och iterera genom den:
std::map<std::string, std::string> replacements = {
{"&lt;", "<"}, {"&gt;", ">"}, {"&nbsp;", " "}, {"&amp;", "&"}
};
for (const auto& [pattern, replacement] : replacements) {
result = std::regex_replace(result, std::regex(pattern), replacement);
}
6. How do you check if an input or output operation on a stream (e.g., operator>> or
operator<<) has failed?
Genom att använda std::istream::fail() eller std::ostream::fail().
7. How do you know if you have reached the end of an istream?
Genom att använda std::istream::eof().
8. Does string_cast<int>("123kalle") return the value 123 or does it throw an exception?
How do you implement each of those behaviours?
Det kastar ett undantag eftersom std::istringstream misslyckas med att konsumera hela strängen. För att tillåta delvis inläsning skulle vi behöva anpassa funktionen.
9. When calling the function template toString, the template type argument is not ex-
plicitly given in the call. For string_cast, on the other hand, you have to specify
string_cast<int> or string_cast<Date>. What is the difference? When should explicit
template arguments be given to function templates?
toString använder <<-operatören, som automatiskt identifierar typen av objekt, medan string_cast kräver en explicit typ eftersom det behöver veta vad strängen ska konverteras till.

14
lab4/string_cast.h Normal file
View file

@ -0,0 +1,14 @@
#include <iostream>
#include <sstream>
#include <stdexcept> // För std::invalid_argument
// Template function for string_cast
template <typename T>
T string_cast(const std::string& str) {
std::istringstream iss(str);
T value;
if (!(iss >> value) || !(iss.eof())) {
throw std::invalid_argument("Invalid conversion from string: " + str);
}
return value;
}

29
lab4/string_cast_test.cc Normal file
View file

@ -0,0 +1,29 @@
#include <iostream>
#include <string>
#include "date.h" // För Date-klassen
#include "string_cast.h" // Inkludera string_cast
int main() {
try {
// Testa string_cast med int
int i = string_cast<int>("123");
std::cout << "Integer: " << i << std::endl;
// Testa string_cast med double
double d = string_cast<double>("12.34");
std::cout << "Double: " << d << std::endl;
// Testa string_cast med Date
Date date = string_cast<Date>("2015-01-10");
std::cout << "Date: " << date << std::endl;
// Testa ogiltig konvertering
int invalid = string_cast<int>("abc");
std::cout << "Invalid conversion: " << invalid << std::endl;
} catch (const std::invalid_argument& e) {
std::cout << "Error: " << e.what() << std::endl;
}
return 0;
}

10
lab4/toString.h Normal file
View file

@ -0,0 +1,10 @@
#include <sstream>
#include <string>
// Template function to convert an object to a string
template <typename T>
std::string toString(const T& obj) {
std::ostringstream oss;
oss << obj;
return oss.str();
}

22
lab4/toString_test.cc Normal file
View file

@ -0,0 +1,22 @@
#include <iostream>
#include "date.h" // Inkludera Date-klassen från tidigare lösning
#include "toString.h" // Inkludera toString-mallen
int main() {
// Testa med ett primitivt datatyper
double d = 1.234;
int i = 42;
std::string strDouble = toString(d);
std::string strInt = toString(i);
std::cout << "Double as string: " << strDouble << std::endl;
std::cout << "Integer as string: " << strInt << std::endl;
// Testa med Date-klassen
Date today(2023, 12, 11); // Skapa ett datumobjekt
std::string strDate = toString(today);
std::cout << "Date as string: " << strDate << std::endl;
return 0;
}