Compare commits

..

1 commit
main ... dDogge

Author SHA1 Message Date
dDogge
4eedfb85f5 lab1 done 2024-11-12 12:53:50 +01:00
92 changed files with 495 additions and 1360 deletions

View file

@ -1,274 +0,0 @@
---
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
View file

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

View file

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

Binary file not shown.

2
lab1/.gitignore vendored
View file

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

View file

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

View file

@ -1,51 +0,0 @@
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,17 +1,58 @@
# The following rule means: "if test_editor does not exist, or # Define the compiler and the linker. The linker must be defined since
# is older than test_editor.o or editor.o, # the implicit rule for linking uses CC as the linker. g++ can be
# then link test_editor". # changed to clang++.
test_editor: test_editor.o editor.o CXX = g++
g++ -o test_editor test_editor.o editor.o CC = $(CXX)
# Rules to create the object files. # Generate dependencies in *.d files
test_editor.o: test_editor.cc editor.h DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
g++ -c test_editor.cc -std=c++11
editor.o: editor.cc editor.h
g++ -c editor.cc -std=c++11
# 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 print_argv: print_argv.o
g++ -o print_argv print_argv.o test_editor: test_editor.o editor.o
print_argv.o: print_argv.cc test_coding: test_coding.o coding.o
g++ -c print_argv.cc -std=c++11 encode: encode.o coding.o
decode: decode.o coding.o
# Phony targets
.PHONY: all test test_encode_decode clean distclean
# Standard clean
clean:
rm -f *.o $(PROGS)
distclean: clean
rm *.d
# Include the *.d files
SRC = $(wildcard *.cc)
-include $(SRC:.cc=.d)

17
lab1/Makefile1 Normal file
View file

@ -0,0 +1,17 @@
# 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

View file

@ -1,50 +0,0 @@
# 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)

View file

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

View file

@ -21,20 +21,30 @@ PROGS=ub leak bounds bounds-heap dangling sum
ALL: $(PROGS) ALL: $(PROGS)
leak: leak.cc leak: leak.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
dangling: dangling.cc dangling: dangling.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
bounds: bounds.cc bounds: bounds.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
ub: ub.cc ub: ub.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
sum: sum.cc sum: sum.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
# Targets
# Phony targets
.PHONY: all clean test .PHONY: all clean test
# Standard clean
clean: clean:
-rm $(PROGS) -rm -f $(PROGS)
-rm -r $(addsuffix .dSYM, $(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

BIN
lab1/buggy_programs/bounds Executable file

Binary file not shown.

BIN
lab1/buggy_programs/bounds-alt Executable file

Binary file not shown.

BIN
lab1/buggy_programs/bounds-heap Executable file

Binary file not shown.

Binary file not shown.

BIN
lab1/buggy_programs/dangling Executable file

Binary file not shown.

BIN
lab1/buggy_programs/leak Executable file

Binary file not shown.

BIN
lab1/buggy_programs/sum Executable file

Binary file not shown.

BIN
lab1/buggy_programs/sum-alt Executable file

Binary file not shown.

BIN
lab1/buggy_programs/ub Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
build

View file

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

2
lab1/coding.d Normal file
View file

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

BIN
lab1/coding.o Normal file

Binary file not shown.

BIN
lab1/decode Executable file

Binary file not shown.

34
lab1/decode.cc Normal file
View file

@ -0,0 +1,34 @@
#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;
}

2
lab1/decode.d Normal file
View file

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

BIN
lab1/decode.o Normal file

Binary file not shown.

View file

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

2
lab1/editor.d Normal file
View file

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

View file

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

BIN
lab1/editor.o Normal file

Binary file not shown.

BIN
lab1/encode Executable file

Binary file not shown.

35
lab1/encode.cc Normal file
View file

@ -0,0 +1,35 @@
#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;
}

2
lab1/encode.d Normal file
View file

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

BIN
lab1/encode.o Normal file

Binary file not shown.

BIN
lab1/hello Executable file

Binary file not shown.

View file

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

1
lab1/hello.d Normal file
View file

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

BIN
lab1/print_argv Executable file

Binary file not shown.

1
lab1/print_argv.d Normal file
View file

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

BIN
lab1/print_argv.o Normal file

Binary file not shown.

49
lab1/reflektion.txt Normal file
View file

@ -0,0 +1,49 @@
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,6 +25,8 @@ PROGS = read-words example-out
all: $(PROGS) all: $(PROGS)
test: ./example-out ./read-words
# Phony targets # Phony targets
.PHONY: all test clean distclean .PHONY: all test clean distclean

View file

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

BIN
lab1/stream-examples/example-out Executable file

Binary file not shown.

View file

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

View file

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

BIN
lab1/stream-examples/read-words Executable file

Binary file not shown.

View file

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

BIN
lab1/test_coding Executable file

Binary file not shown.

2
lab1/test_coding.d Normal file
View file

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

BIN
lab1/test_coding.o Normal file

Binary file not shown.

BIN
lab1/test_editor Executable file

Binary file not shown.

2
lab1/test_editor.d Normal file
View file

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

BIN
lab1/test_editor.o Normal file

Binary file not shown.

1
lab1/testfile.txt Normal file
View file

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

1
lab1/testfile.txt.dec Normal file
View file

@ -0,0 +1 @@
Fcjjmkwl_kcgqBmsej_q

1
lab1/testfile.txt.enc Normal file
View file

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

View file

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

View file

@ -1,37 +0,0 @@
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,131 +1,22 @@
#include "dictionary.h"
#include "edit_distance.h"
#include "word.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
#include "word.h"
#include "dictionary.h"
using std::string; using std::string;
using std::vector; 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;
} }
std::vector<string> Dictionary::get_suggestions(const string &word) const { bool Dictionary::contains(const string& word) const {
vector<string> suggestions; return true;
add_trigram_suggestions(suggestions, word);
trim_suggestions(suggestions, word);
rank_suggestions(suggestions, word);
return suggestions;
} }
void Dictionary::add_trigram_suggestions(std::vector<std::string> &suggestions, vector<string> Dictionary::get_suggestions(const string& word) const {
const std::string &word) const { vector<string> suggestions;
// Get trigrams of the input word return suggestions;
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,29 +1,15 @@
#pragma once #ifndef DICTIONARY_H
#define DICTIONARY_H
#include "word.h"
#include <filesystem>
#include <string> #include <string>
#include <vector> #include <vector>
#define MAXLEN 30
// using std::vector;
using std::filesystem::path;
class Dictionary { class Dictionary {
public: public:
Dictionary(); Dictionary();
void add_trigram_suggestions(std::vector<std::string> &suggestions, bool contains(const std::string& word) const;
const std::string &word) const; std::vector<std::string> get_suggestions(const std::string& word) const;
void rank_suggestions(std::vector<std::string> &suggestions, private:
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];
}; };
#endif

View file

@ -1,35 +0,0 @@
#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]);
}

View file

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

View file

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

View file

@ -1,63 +1,16 @@
#include "word.h"
#include "dictionary.h"
#include <algorithm>
#include <string> #include <string>
#include <vector> #include <vector>
#include "word.h"
using std::string;
using std::vector; using std::vector;
using std::string;
Word::Word(const string &w, const vector<string> &t) : word(w), trigrams(t) { Word::Word(const string& w, const vector<string>& t) {}
std::sort(trigrams.begin(), trigrams.end());
string Word::get_word() const {
return string();
} }
std::vector<std::string> get_trigrams(const std::string &text) { unsigned int Word::get_matches(const vector<string>& t) const {
std::vector<std::string> trigrams; return 0;
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,34 +1,21 @@
#pragma once #ifndef WORD_H
#define WORD_H
#include <string> #include <string>
#include <vector> #include <vector>
/*
* Contains a word and its trigrams
*/
class Word { class Word {
public: public:
/** Creates a word w with the sorted trigrams t */ /* Creates a word w with the sorted trigrams t */
Word(const std::string &w, const std::vector<std::string> &t); Word(const std::string& w, const std::vector<std::string>& t);
/** Creates a word w and derives the trigrams internally */ /* Returns the word */
Word(const std::string &w); std::string get_word() const;
/** Returns the word */ /* Returns how many of the trigrams in t that are present
std::string get_word() const; in this word's trigram vector */
unsigned int get_matches(const std::vector<std::string>& t) const;
/** Returns trigrams */ private:
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);
}; };
bool operator==(const Word &lhs, const Word &rhs); #endif

View file

@ -1,33 +0,0 @@
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,5 +1,6 @@
#include "User.h" #include "User.h"
std::ostream &operator<<(std::ostream &os, const User &u) { std::ostream& operator<<(std::ostream& os, const User& u)
return os << "(" << u.getCardNbr() << ") " << u.getName(); {
return os << "(" << u.getCardNbr() << ") "<< u.getName();
} }

View file

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

View file

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

View file

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

View file

@ -1,42 +0,0 @@
#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

@ -1,74 +0,0 @@
#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;
}

View file

@ -1,32 +0,0 @@
#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,86 +1,30 @@
#include <ctime> // för tid och localtime #include <ctime> // time and localtime
#include <iomanip> // för setw och setfill
#include <sstream> // för inputhantering
#include "date.h" #include "date.h"
int Date::daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int Date::daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// Konstruktor: dagens datum
Date::Date() { Date::Date() {
time_t timer = time(0); // tid i sekunder sedan 1970-01-01 time_t timer = time(0); // time in seconds since 1970-01-01
tm* locTime = localtime(&timer); // lokal tid tm* locTime = localtime(&timer); // broken-down time
year = 1900 + locTime->tm_year; year = 1900 + locTime->tm_year;
month = 1 + locTime->tm_mon; month = 1 + locTime->tm_mon;
day = locTime->tm_mday; day = locTime->tm_mday;
} }
// Konstruktor: specifikt datum Date::Date(int y, int m, int d) {}
Date::Date(int y, int m, int d) : year(y), month(m), day(d) {}
// Get-funktioner
int Date::getYear() const { int Date::getYear() const {
return year; return 0;
} }
int Date::getMonth() const { int Date::getMonth() const {
return month; return 0;
} }
int Date::getDay() const { int Date::getDay() const {
return day; return 0;
} }
// Gå till nästa dag
void Date::next() { 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,27 +1,19 @@
#ifndef DATE_H #ifndef DATE_H
#define DATE_H #define DATE_H
#include <iostream>
class Date { class Date {
public: public:
Date(); // dagens datum Date(); // today's date
Date(int y, int m, int d); // yyyy-mm-dd Date(int y, int m, int d); // yyyy-mm-dd
int getYear() const; // returnerar året int getYear() const; // get the year
int getMonth() const; // returnerar månaden int getMonth() const; // get the month
int getDay() const; // returnerar dagen int getDay() const; // get the day
void next(); // går till nästa dag void next(); // advance to next day
// Overloaded operators
friend std::ostream& operator<<(std::ostream& os, const Date& date);
friend std::istream& operator>>(std::istream& is, Date& date);
private: private:
int year; // året (fyra siffror) int year; // the year (four digits)
int month; // månaden (1-12) int month; // the month (1-12)
int day; // dagen (1-...) int day; // the day (1-..)
static int daysPerMonth[12]; // antal dagar i varje månad static int daysPerMonth[12]; // number of days in each month
static bool isLeapYear(int year); // kontrollera skottår
}; };
#endif #endif

View file

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

View file

@ -1,56 +0,0 @@
# 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

View file

@ -1,61 +0,0 @@
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.

View file

@ -1,14 +0,0 @@
#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;
}

View file

@ -1,29 +0,0 @@
#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;
}

View file

@ -1,10 +0,0 @@
#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();
}

View file

@ -1,22 +0,0 @@
#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;
}