Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
4eedfb85f5 |
92 changed files with 495 additions and 1360 deletions
274
.clang-format
274
.clang-format
|
@ -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
11
.gitignore
vendored
|
@ -1,11 +0,0 @@
|
||||||
*.o
|
|
||||||
*.d
|
|
||||||
*a.out*
|
|
||||||
build
|
|
||||||
.cache/
|
|
||||||
words.txt
|
|
||||||
compile_commands.json
|
|
||||||
lab2/edit
|
|
||||||
lab2/spell
|
|
||||||
lab3/tabletest
|
|
||||||
./vscode
|
|
2
Makefile
2
Makefile
|
@ -1,2 +0,0 @@
|
||||||
format:
|
|
||||||
find . -regex '.*\.\(c\|cpp\|cc\|cxx\|h\|hpp\|hh\|hxx\)' -exec clang-format {} +
|
|
BIN
cpplabs.pdf
BIN
cpplabs.pdf
Binary file not shown.
2
lab1/.gitignore
vendored
2
lab1/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
hello
|
|
||||||
test_editor
|
|
|
@ -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",
|
|
@ -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
|
|
|
@ -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
17
lab1/Makefile1
Normal 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
|
||||||
|
|
|
@ -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)
|
|
6
lab1/buggy_programs/.gitignore
vendored
6
lab1/buggy_programs/.gitignore
vendored
|
@ -1,6 +0,0 @@
|
||||||
bounds
|
|
||||||
bounds-heap
|
|
||||||
dangling
|
|
||||||
leak
|
|
||||||
sum
|
|
||||||
ub
|
|
|
@ -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
BIN
lab1/buggy_programs/bounds
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/bounds-alt
Executable file
BIN
lab1/buggy_programs/bounds-alt
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/bounds-heap
Executable file
BIN
lab1/buggy_programs/bounds-heap
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/bounds-heap-alt
Executable file
BIN
lab1/buggy_programs/bounds-heap-alt
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/dangling
Executable file
BIN
lab1/buggy_programs/dangling
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/leak
Executable file
BIN
lab1/buggy_programs/leak
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/sum
Executable file
BIN
lab1/buggy_programs/sum
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/sum-alt
Executable file
BIN
lab1/buggy_programs/sum-alt
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/ub
Executable file
BIN
lab1/buggy_programs/ub
Executable file
Binary file not shown.
BIN
lab1/buggy_programs/vgcore.12684
Normal file
BIN
lab1/buggy_programs/vgcore.12684
Normal file
Binary file not shown.
BIN
lab1/buggy_programs/vgcore.13027
Normal file
BIN
lab1/buggy_programs/vgcore.13027
Normal file
Binary file not shown.
BIN
lab1/buggy_programs/vgcore.13797
Normal file
BIN
lab1/buggy_programs/vgcore.13797
Normal file
Binary file not shown.
1
lab1/cmake-example/.gitignore
vendored
1
lab1/cmake-example/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
build
|
|
|
@ -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
2
lab1/coding.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
coding.o: coding.cc coding.h
|
||||||
|
coding.h:
|
BIN
lab1/coding.o
Normal file
BIN
lab1/coding.o
Normal file
Binary file not shown.
BIN
lab1/decode
Executable file
BIN
lab1/decode
Executable file
Binary file not shown.
34
lab1/decode.cc
Normal file
34
lab1/decode.cc
Normal 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
2
lab1/decode.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
decode.o: decode.cc coding.h
|
||||||
|
coding.h:
|
BIN
lab1/decode.o
Normal file
BIN
lab1/decode.o
Normal file
Binary file not shown.
|
@ -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
2
lab1/editor.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
editor.o: editor.cc editor.h
|
||||||
|
editor.h:
|
|
@ -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
BIN
lab1/editor.o
Normal file
Binary file not shown.
BIN
lab1/encode
Executable file
BIN
lab1/encode
Executable file
Binary file not shown.
35
lab1/encode.cc
Normal file
35
lab1/encode.cc
Normal 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
2
lab1/encode.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
encode.o: encode.cc coding.h
|
||||||
|
coding.h:
|
BIN
lab1/encode.o
Normal file
BIN
lab1/encode.o
Normal file
Binary file not shown.
BIN
lab1/hello
Executable file
BIN
lab1/hello
Executable file
Binary file not shown.
|
@ -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
1
lab1/hello.d
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello: hello.cc
|
BIN
lab1/print_argv
Executable file
BIN
lab1/print_argv
Executable file
Binary file not shown.
1
lab1/print_argv.d
Normal file
1
lab1/print_argv.d
Normal file
|
@ -0,0 +1 @@
|
||||||
|
print_argv.o: print_argv.cc
|
BIN
lab1/print_argv.o
Normal file
BIN
lab1/print_argv.o
Normal file
Binary file not shown.
49
lab1/reflektion.txt
Normal file
49
lab1/reflektion.txt
Normal 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; it’s 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) ... doesn’t
|
||||||
|
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.
|
|
@ -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
|
||||||
|
|
||||||
|
|
2
lab1/stream-examples/err.txt
Normal file
2
lab1/stream-examples/err.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
And this is written to stderr
|
||||||
|
And some more to stderr
|
BIN
lab1/stream-examples/example-out
Executable file
BIN
lab1/stream-examples/example-out
Executable file
Binary file not shown.
1
lab1/stream-examples/example-out.d
Normal file
1
lab1/stream-examples/example-out.d
Normal file
|
@ -0,0 +1 @@
|
||||||
|
example-out: example-out.cc
|
2
lab1/stream-examples/out.txt
Normal file
2
lab1/stream-examples/out.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
This text is written to stdout
|
||||||
|
More text to stdout
|
BIN
lab1/stream-examples/read-words
Executable file
BIN
lab1/stream-examples/read-words
Executable file
Binary file not shown.
1
lab1/stream-examples/read-words.d
Normal file
1
lab1/stream-examples/read-words.d
Normal file
|
@ -0,0 +1 @@
|
||||||
|
read-words: read-words.cc
|
BIN
lab1/test_coding
Executable file
BIN
lab1/test_coding
Executable file
Binary file not shown.
2
lab1/test_coding.d
Normal file
2
lab1/test_coding.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
test_coding.o: test_coding.cc coding.h
|
||||||
|
coding.h:
|
BIN
lab1/test_coding.o
Normal file
BIN
lab1/test_coding.o
Normal file
Binary file not shown.
BIN
lab1/test_editor
Executable file
BIN
lab1/test_editor
Executable file
Binary file not shown.
2
lab1/test_editor.d
Normal file
2
lab1/test_editor.d
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
test_editor.o: test_editor.cc editor.h
|
||||||
|
editor.h:
|
BIN
lab1/test_editor.o
Normal file
BIN
lab1/test_editor.o
Normal file
Binary file not shown.
1
lab1/testfile.txt
Normal file
1
lab1/testfile.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello my name is Douglas
|
1
lab1/testfile.txt.dec
Normal file
1
lab1/testfile.txt.dec
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fcjjmkwl_kcgqBmsej_q
|
1
lab1/testfile.txt.enc
Normal file
1
lab1/testfile.txt.enc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Jgnnq"o{"pcog"ku"Fqwincu
|
1
lab1/testfile.txt.enc.dec
Normal file
1
lab1/testfile.txt.enc.dec
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello my name is Douglas
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]);
|
|
||||||
}
|
|
|
@ -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);
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
63
lab2/word.cc
63
lab2/word.cc
|
@ -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());
|
|
||||||
}
|
}
|
||||||
|
|
37
lab2/word.h
37
lab2/word.h
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
30
lab3/User.h
30
lab3/User.h
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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("<"), "<");
|
|
||||||
result = std::regex_replace(result, std::regex(">"), ">");
|
|
||||||
result = std::regex_replace(result, std::regex(" "), " ");
|
|
||||||
result = std::regex_replace(result, std::regex("&"), "&");
|
|
||||||
|
|
||||||
output << result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
TagRemover tr(std::cin);
|
|
||||||
tr.print(std::cout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
76
lab4/date.cc
76
lab4/date.cc
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
28
lab4/date.h
28
lab4/date.h
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
|
@ -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 = {
|
|
||||||
{"<", "<"}, {">", ">"}, {" ", " "}, {"&", "&"}
|
|
||||||
};
|
|
||||||
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.
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in a new issue