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",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"clocale": "cpp",
|
||||
|
@ -32,13 +31,13 @@
|
|||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"regex": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
|
@ -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
|
||||
# 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
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
# Generate dependencies in *.d files
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
|
||||
|
||||
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
|
||||
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
|
||||
# -g is for debugging.
|
||||
CPPFLAGS = -std=c++11 -I.
|
||||
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
|
||||
CXXFLAGS += -std=c++11
|
||||
CXXFLAGS += -g
|
||||
CXXFLAGS += $(DEPFLAGS)
|
||||
LDFLAGS = -g
|
||||
#CPPFLAGS += -stdlib=libc++
|
||||
#CXXFLAGS += -stdlib=libc++
|
||||
#LDFLAGS += -stdlib=libc++
|
||||
|
||||
# Targets
|
||||
PROGS = test_editor test_coding print_argv hello encode decode
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
test: test_coding test_editor
|
||||
./test_coding
|
||||
./test_editor
|
||||
./hello
|
||||
|
||||
test_encode_decode: encode decode
|
||||
@echo "Running encode-decode tests"
|
||||
./encode testfile.txt
|
||||
./decode testfile.txt.enc
|
||||
|
||||
# Targets rely on implicit rules for compiling and linking
|
||||
print_argv: print_argv.o
|
||||
g++ -o print_argv print_argv.o
|
||||
print_argv.o: print_argv.cc
|
||||
g++ -c print_argv.cc -std=c++11
|
||||
test_editor: test_editor.o editor.o
|
||||
test_coding: test_coding.o coding.o
|
||||
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
|
|
@ -3,7 +3,7 @@
|
|||
# It uses generator expressions, to set additional flags when the build type
|
||||
# is Debug.
|
||||
#
|
||||
# To try this out, first create a build directory for a release build,
|
||||
# To try this out, first create a build directory for a release build,
|
||||
# and do a release build, e.g.,
|
||||
# % mkdir build-rel
|
||||
# % cd build-rel
|
||||
|
@ -21,7 +21,7 @@
|
|||
#
|
||||
# where SRC_DIR is the directory containing the source and CMakeLists.txt,
|
||||
# e.g., .. if your build directories are placed in this directory.
|
||||
#
|
||||
#
|
||||
# Run the examples and verify that the sanitizers find the errors.
|
||||
#
|
||||
# If you want to see the actual commands run during the build, for instance
|
||||
|
|
|
@ -21,20 +21,30 @@ PROGS=ub leak bounds bounds-heap dangling sum
|
|||
ALL: $(PROGS)
|
||||
|
||||
leak: leak.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
dangling: dangling.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
bounds: bounds.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
ub: ub.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
sum: sum.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
# Targets
|
||||
# Phony targets
|
||||
.PHONY: all clean test
|
||||
|
||||
# Standard clean
|
||||
clean:
|
||||
-rm $(PROGS)
|
||||
-rm -r $(addsuffix .dSYM, $(PROGS))
|
||||
-rm -f $(PROGS)
|
||||
-rm -rf $(addsuffix .dSYM, $(PROGS))
|
||||
|
||||
test: $(PROGS)
|
||||
@echo "Running tests with Valgrind..."
|
||||
@for prog in $(PROGS); do \
|
||||
echo "Testing $$prog with Valgrind:"; \
|
||||
valgrind ./$$prog; \
|
||||
echo ""; \
|
||||
done
|
||||
|
|
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) {
|
||||
return ++c;
|
||||
unsigned char encode(unsigned char c)
|
||||
{
|
||||
return c + 2;
|
||||
}
|
||||
|
||||
unsigned char decode(unsigned char c) {
|
||||
return --c;
|
||||
unsigned char decode(unsigned char 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;
|
||||
|
||||
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 {
|
||||
char right_par = text[pos];
|
||||
char left_par;
|
||||
|
||||
// Determine the matching left parenthesis for the given right parenthesis
|
||||
switch (right_par) {
|
||||
case ')': left_par = '('; break;
|
||||
case ']': left_par = '['; break;
|
||||
case '}': left_par = '{'; break;
|
||||
default: return string::npos; // Not a valid right parenthesis
|
||||
size_type Editor::find_left_par(size_type pos) const {
|
||||
if (pos >= text.size() || (text[pos] != ')' && text[pos] != ']' && text[pos] != '}')) {
|
||||
return std::string::npos;
|
||||
}
|
||||
|
||||
int balance = 1; // Start with the right parenthesis at text[pos]
|
||||
for (size_type i = pos; i-- > 0;) {
|
||||
if (text[i] == left_par) {
|
||||
balance--;
|
||||
if (balance == 0) return i; // Found the matching left parenthesis
|
||||
} else if (text[i] == right_par) {
|
||||
char right_par = text[pos];
|
||||
char left_par = (right_par == ')') ? '(' : (right_par == ']') ? '[' : '{';
|
||||
|
||||
int balance = 0;
|
||||
|
||||
for (int i = pos; i >= 0; --i) {
|
||||
if (text[i] == right_par) {
|
||||
balance++;
|
||||
} else if (text[i] == left_par) {
|
||||
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>
|
||||
|
||||
class Editor {
|
||||
public:
|
||||
public:
|
||||
using size_type = std::string::size_type;
|
||||
/* Creates a text editor containing the text t */
|
||||
Editor(const std::string &t) : text(t) {}
|
||||
/* Creates a text editor containing the text t */
|
||||
Editor(const std::string& t) : text(t) {}
|
||||
|
||||
/* Get the size of the current contents */
|
||||
size_type get_size() const;
|
||||
|
||||
/*
|
||||
* Text[pos] contains a right parentheses. Returns the position of
|
||||
* the corresponding left parentheses, or string::npos if there
|
||||
* is no match.
|
||||
*/
|
||||
size_type find_left_par(size_type pos) const;
|
||||
/*
|
||||
* Text[pos] contains a right parentheses. Returns the position of
|
||||
* the corresponding left parentheses, or string::npos if there
|
||||
* is no match.
|
||||
*/
|
||||
size_type find_left_par(size_type pos) const;
|
||||
|
||||
// ... functions to edit the text (insert and delete characters)
|
||||
private:
|
||||
std::string text;
|
||||
// ... functions to edit the text (insert and delete characters)
|
||||
private:
|
||||
std::string text;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
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>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
std::cout << "Hello" << std::endl;
|
||||
}
|
||||
int main() {
|
||||
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)
|
||||
|
||||
test: ./example-out ./read-words
|
||||
|
||||
# Phony targets
|
||||
.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 <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include "word.h"
|
||||
#include "dictionary.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
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;
|
||||
Dictionary::Dictionary() {
|
||||
}
|
||||
|
||||
std::vector<string> Dictionary::get_suggestions(const string &word) const {
|
||||
vector<string> suggestions;
|
||||
add_trigram_suggestions(suggestions, word);
|
||||
trim_suggestions(suggestions, word);
|
||||
rank_suggestions(suggestions, word);
|
||||
return suggestions;
|
||||
bool Dictionary::contains(const string& word) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dictionary::add_trigram_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Get trigrams of the input word
|
||||
Word input_word(word);
|
||||
const std::vector<std::string> &input_trigrams = input_word.get_trigrams();
|
||||
|
||||
// Iterate through all words in the dictionary
|
||||
for (int i = 0; i < MAXLEN; ++i) {
|
||||
for (const Word &dict_word : words[i]) {
|
||||
// Get the trigrams of the dictionary word
|
||||
const std::vector<std::string> &dict_word_trigrams =
|
||||
dict_word.get_trigrams();
|
||||
|
||||
// Count how many trigrams match
|
||||
unsigned int match_count = dict_word.get_matches(input_trigrams);
|
||||
|
||||
// If there are any matches, add the word to suggestions
|
||||
if (match_count > 0) {
|
||||
suggestions.push_back(dict_word.get_word());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dictionary::rank_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Sort suggestions based on the levenshtein distance
|
||||
std::sort(suggestions.begin(), suggestions.end(),
|
||||
[&](const std::string &a, const std::string &b) {
|
||||
auto dist_a = edit_distance(a, word);
|
||||
auto dist_b = edit_distance(b, word);
|
||||
return dist_a < dist_b;
|
||||
});
|
||||
}
|
||||
|
||||
void Dictionary::trim_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Remove duplicates using a set
|
||||
std::set<std::string> unique_suggestions(suggestions.begin(),
|
||||
suggestions.end());
|
||||
suggestions.assign(unique_suggestions.begin(), unique_suggestions.end());
|
||||
|
||||
// Remove the input word from the suggestions list (if present)
|
||||
suggestions.erase(std::remove(suggestions.begin(), suggestions.end(), word),
|
||||
suggestions.end());
|
||||
|
||||
auto l = word.length();
|
||||
std::cout << "WTF" << l << std::endl;
|
||||
|
||||
// Example: Remove any suggestions that are not within 1 string length
|
||||
suggestions.erase(std::remove_if(suggestions.begin(), suggestions.end(),
|
||||
[l](const std::string &s) {
|
||||
return s.length() > (l + 1) ||
|
||||
s.length() < (l - 1);
|
||||
}),
|
||||
suggestions.end());
|
||||
}
|
||||
|
||||
int Dictionary::spit(path p) {
|
||||
std::ofstream file(p);
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file! " << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int a = 0; a < MAXLEN; a++) {
|
||||
for (auto &word : words[a]) {
|
||||
file << word;
|
||||
file << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
file.flush();
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dictionary::slurp(path p) {
|
||||
std::ifstream file(p.string());
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file! " << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
// Words larger than max gets placed in the topmost bucket
|
||||
words[std::min(line.size(), static_cast<size_t>(MAXLEN) - 1)].push_back(
|
||||
Word(line));
|
||||
}
|
||||
|
||||
file.close();
|
||||
return 0;
|
||||
vector<string> Dictionary::get_suggestions(const string& word) const {
|
||||
vector<string> suggestions;
|
||||
return suggestions;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,15 @@
|
|||
#pragma once
|
||||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
|
||||
#include "word.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define MAXLEN 30
|
||||
|
||||
// using std::vector;
|
||||
using std::filesystem::path;
|
||||
|
||||
class Dictionary {
|
||||
public:
|
||||
Dictionary();
|
||||
void add_trigram_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
void rank_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
void trim_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
bool contains(const std::string &word) const;
|
||||
std::vector<std::string> get_suggestions(const std::string &word) const;
|
||||
int slurp(path p);
|
||||
int spit(path p);
|
||||
|
||||
private:
|
||||
std::vector<Word> words[MAXLEN];
|
||||
public:
|
||||
Dictionary();
|
||||
bool contains(const std::string& word) const;
|
||||
std::vector<std::string> get_suggestions(const std::string& word) const;
|
||||
private:
|
||||
};
|
||||
|
||||
#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 <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
#include "dictionary.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
void check_word(const string &word, const Dictionary &dict) {
|
||||
void check_word(const string& word, const Dictionary& dict)
|
||||
{
|
||||
if (dict.contains(word)) {
|
||||
cout << "Correct." << endl;
|
||||
} else {
|
||||
|
@ -21,22 +21,18 @@ void check_word(const string &word, const Dictionary &dict) {
|
|||
cout << "Wrong, no suggestions." << endl;
|
||||
} else {
|
||||
cout << "Wrong. Suggestions:" << endl;
|
||||
for (const auto &w : suggestions) {
|
||||
for (const auto& w : suggestions) {
|
||||
cout << " " << w << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
Dictionary dict;
|
||||
string word;
|
||||
dict.slurp(std::filesystem::path("/usr/share/dict/words"));
|
||||
// dict.spit(std::filesystem::path("words.txt"));
|
||||
|
||||
while (cin >> word) {
|
||||
std::transform(word.begin(), word.end(), word.begin(), ::tolower);
|
||||
Dictionary dict;
|
||||
string word;
|
||||
while (cin >> word) {
|
||||
transform(word.begin(), word.end(), word.begin(), ::tolower);
|
||||
check_word(word, dict);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
bool do_test(const std::string &x, const std::string &y, int expected) {
|
||||
bool do_test(const std::string& x, const std::string& y, int expected)
|
||||
{
|
||||
auto actual = edit_distance(x, y);
|
||||
if (actual != expected) {
|
||||
std::cout << "*** WRONG: distance(" << x << ", " << y << ") was "
|
||||
|
@ -18,7 +19,8 @@ bool do_test(const std::string &x, const std::string &y, int expected) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int main()
|
||||
{
|
||||
int res = do_test("foobar", "foobar", 0);
|
||||
res += do_test("x", "x", 0);
|
||||
res += do_test("baz", "bar", 1);
|
||||
|
|
63
lab2/word.cc
63
lab2/word.cc
|
@ -1,63 +1,16 @@
|
|||
#include "word.h"
|
||||
#include "dictionary.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "word.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
Word::Word(const string &w, const vector<string> &t) : word(w), trigrams(t) {
|
||||
std::sort(trigrams.begin(), trigrams.end());
|
||||
Word::Word(const string& w, const vector<string>& t) {}
|
||||
|
||||
string Word::get_word() const {
|
||||
return string();
|
||||
}
|
||||
|
||||
std::vector<std::string> get_trigrams(const std::string &text) {
|
||||
std::vector<std::string> trigrams;
|
||||
if (text.size() < 3) {
|
||||
return trigrams; // Return an empty vector if the input is too short
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <= text.size() - 3; ++i) {
|
||||
trigrams.push_back(
|
||||
text.substr(i, 3)); // Extract a substring of length 3
|
||||
}
|
||||
|
||||
return trigrams;
|
||||
}
|
||||
|
||||
Word::Word(const std::string &w) : word(w) {
|
||||
this->trigrams = ::get_trigrams(w);
|
||||
std::sort(trigrams.begin(), trigrams.end());
|
||||
}
|
||||
|
||||
string Word::get_word() const { return word; }
|
||||
|
||||
vector<std::string> Word::get_trigrams() const { return trigrams; }
|
||||
|
||||
unsigned int Word::get_matches(const vector<string> &t) const {
|
||||
unsigned int matches = 0;
|
||||
|
||||
for (const auto &trigram : t) {
|
||||
if (std::binary_search(trigrams.begin(), trigrams.end(), trigram)) {
|
||||
++matches;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Word &w) {
|
||||
auto space = string(" ");
|
||||
out << w.word;
|
||||
out << space;
|
||||
out << w.trigrams.size();
|
||||
for (const auto &tri : w.trigrams) {
|
||||
out << space << tri;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool operator==(const Word &lhs, const Word &rhs) {
|
||||
return lhs.word == rhs.word &&
|
||||
std::equal(lhs.trigrams.begin(), lhs.trigrams.end(),
|
||||
rhs.trigrams.begin());
|
||||
unsigned int Word::get_matches(const vector<string>& t) const {
|
||||
return 0;
|
||||
}
|
||||
|
|
41
lab2/word.h
41
lab2/word.h
|
@ -1,34 +1,21 @@
|
|||
#pragma once
|
||||
#ifndef WORD_H
|
||||
#define WORD_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
* Contains a word and its trigrams
|
||||
*/
|
||||
class Word {
|
||||
public:
|
||||
/** Creates a word w with the sorted trigrams t */
|
||||
Word(const std::string &w, const std::vector<std::string> &t);
|
||||
|
||||
/** Creates a word w and derives the trigrams internally */
|
||||
Word(const std::string &w);
|
||||
|
||||
/** Returns the word */
|
||||
std::string get_word() const;
|
||||
|
||||
/** Returns trigrams */
|
||||
std::vector<std::string> get_trigrams() const;
|
||||
|
||||
/** Returns how many of the trigrams in t that are present
|
||||
in this word's trigram vector */
|
||||
unsigned int get_matches(const std::vector<std::string> &t) const;
|
||||
|
||||
private:
|
||||
const std::string word;
|
||||
std::vector<std::string> trigrams;
|
||||
friend std::ostream &operator<<(std::ostream &out, const Word &o);
|
||||
friend bool operator==(const Word &lhs, const Word &rhs);
|
||||
public:
|
||||
/* Creates a word w with the sorted trigrams t */
|
||||
Word(const std::string& w, const std::vector<std::string>& t);
|
||||
|
||||
/* Returns the word */
|
||||
std::string get_word() const;
|
||||
|
||||
/* 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:
|
||||
};
|
||||
|
||||
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"
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const User &u) {
|
||||
return os << "(" << u.getCardNbr() << ") " << u.getName();
|
||||
std::ostream& operator<<(std::ostream& os, const User& u)
|
||||
{
|
||||
return os << "(" << u.getCardNbr() << ") "<< u.getName();
|
||||
}
|
||||
|
|
30
lab3/User.h
30
lab3/User.h
|
@ -8,26 +8,20 @@ using std::cout;
|
|||
using std::endl;
|
||||
|
||||
class User {
|
||||
public:
|
||||
User() : cardNbr{0}, name{"default"} {}
|
||||
User(int c, std::string n) : cardNbr{c}, name{n} {}
|
||||
~User() {
|
||||
cardNbr = -2;
|
||||
name = "--------------------";
|
||||
} // overwrite values for security reasons
|
||||
User(const User &u) = default;
|
||||
User &operator=(const User &) = default;
|
||||
int getCardNbr() const { return cardNbr; }
|
||||
std::string getName() const { return name; }
|
||||
bool operator==(const User &u) const {
|
||||
return cardNbr == u.cardNbr && name == u.name;
|
||||
}
|
||||
bool operator!=(const User &u) const { return !(u == *this); }
|
||||
|
||||
private:
|
||||
public:
|
||||
User() :cardNbr{0},name{"default"}{}
|
||||
User(int c, std::string n) :cardNbr{c},name{n} {}
|
||||
~User() {cardNbr=-2; name="--------------------";} // overwrite values for security reasons
|
||||
User(const User& u) =default;
|
||||
User& operator=(const User&) =default;
|
||||
int getCardNbr() const {return cardNbr;}
|
||||
std::string getName() const {return name;}
|
||||
bool operator==(const User& u) const {return cardNbr == u.cardNbr && name == u.name;}
|
||||
bool operator!=(const User& u) const {return ! (u == *this);}
|
||||
private:
|
||||
int cardNbr;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const User &u);
|
||||
std::ostream& operator<<(std::ostream& os, const User& u);
|
||||
#endif
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
#include "UserTable.h"
|
||||
#include <algorithm>
|
||||
#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);
|
||||
|
||||
if (ufile.is_open()) {
|
||||
while (ufile) {
|
||||
if(ufile.is_open()) {
|
||||
while(ufile) {
|
||||
int cn;
|
||||
if (ufile >> cn) {
|
||||
if(ufile >> cn ) {
|
||||
ufile.ignore(); // skip space
|
||||
char n[80];
|
||||
ufile.getline(n, 80);
|
||||
addUser(User(cn, n));
|
||||
ufile.getline(n,80);
|
||||
addUser(User(cn,n));
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -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
|
||||
ensureCapacity(n + 1);
|
||||
|
||||
ensureCapacity(n+1);
|
||||
// 1. Hitta rätt plats
|
||||
int pos{0};
|
||||
while ((pos < n) && (users[pos].getCardNbr() < u.getCardNbr())) {
|
||||
while ( (pos < n) && (users[pos].getCardNbr() < u.getCardNbr())){
|
||||
++pos;
|
||||
}
|
||||
|
||||
// 2. skapa lucka i vektorn
|
||||
for (int i = n; i > pos; --i) {
|
||||
users[i] = users[i - 1];
|
||||
//2. skapa lucka i vektorn
|
||||
for(int i=n; i > pos; --i){
|
||||
users[i] = users[i-1];
|
||||
}
|
||||
|
||||
// 3. stoppa in den nya användaren i luckan
|
||||
//3. stoppa in den nya användaren i luckan
|
||||
users[pos] = u;
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
User UserTable::find(int c) const {
|
||||
User UserTable::find(int c) const
|
||||
{
|
||||
// binärsökning (baserad på Holm, 2007)
|
||||
|
||||
int low = 0;
|
||||
int high = n - 1;
|
||||
int mid = -1;
|
||||
bool found = false;
|
||||
while (low < high && !found) {
|
||||
while (low < high && ! found) {
|
||||
mid = (low + high) / 2;
|
||||
//
|
||||
const int midnbr = users[mid].getCardNbr();
|
||||
if (c == midnbr) {
|
||||
int midnbr = users[mid].getCardNbr();
|
||||
if (midnbr = c) {
|
||||
found = true;
|
||||
} else if (users[mid].getCardNbr() < c) {
|
||||
low = mid + 1;
|
||||
|
@ -67,41 +68,48 @@ User UserTable::find(int c) const {
|
|||
|
||||
return found ? users[mid] : user_not_found;
|
||||
}
|
||||
User UserTable::find(std::string name) const {
|
||||
auto it = std::find_if(users, users + n, [&name](const User &u) {
|
||||
return u.getName() == name;
|
||||
});
|
||||
|
||||
// If it is at the 'end' of users, the result is not found
|
||||
return (it != users+n) ? *it : user_not_found;
|
||||
User UserTable::find(std::string name) const
|
||||
{
|
||||
for (int i = 0; i != n; ++i) {
|
||||
if (users[i].getName() == name) {
|
||||
return users[i];
|
||||
} else {
|
||||
return user_not_found;
|
||||
}
|
||||
}
|
||||
return user_not_found;
|
||||
}
|
||||
|
||||
void UserTable::ensureCapacity(int s) {
|
||||
if (s > capacity) {
|
||||
while (s > capacity) {
|
||||
capacity *= 4;
|
||||
void UserTable::ensureCapacity(int s)
|
||||
{
|
||||
if(s>capacity) {
|
||||
while(s > capacity) {
|
||||
capacity*=4;
|
||||
}
|
||||
auto tmp = new User[capacity];
|
||||
std::copy(users, users + n, tmp);
|
||||
std::copy(users, users+n, tmp);
|
||||
delete[] users;
|
||||
users = tmp;
|
||||
users=tmp;
|
||||
}
|
||||
|
||||
}
|
||||
void UserTable::print(std::ostream &os) const {
|
||||
void UserTable::print(std::ostream& os) const
|
||||
{
|
||||
os << "-------------" << std::endl;
|
||||
for (int i = 0; i != getNbrUsers(); ++i) {
|
||||
const auto &u = users[i];
|
||||
os << "(" << u.getCardNbr() << ") " << u.getName() << std::endl;
|
||||
for(int i = 0; i != getNbrUsers(); ++i) {
|
||||
const auto& u = users[i];
|
||||
os << "(" <<u.getCardNbr() << ") " << u.getName() << std::endl;
|
||||
}
|
||||
os << "=============" << std::endl;
|
||||
}
|
||||
/**
|
||||
* Testmetod för binärsökningen:
|
||||
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
|
||||
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
|
||||
* alla sökningar lyckades, returneras 0.
|
||||
*/
|
||||
int testFindNbr(const UserTable ut) {
|
||||
* Testmetod för binärsökningen:
|
||||
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
|
||||
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
|
||||
* alla sökningar lyckades, returneras 0.
|
||||
*/
|
||||
int testFindNbr(const UserTable ut)
|
||||
{
|
||||
for (int i = 0; i < ut.n; i++) {
|
||||
int nbr = ut.users[i].getCardNbr();
|
||||
User found = ut.find(nbr);
|
||||
|
@ -111,3 +119,4 @@ int testFindNbr(const UserTable ut) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,27 +5,28 @@
|
|||
|
||||
#include "User.h"
|
||||
|
||||
class UserTable {
|
||||
public:
|
||||
class UserTable{
|
||||
public:
|
||||
UserTable();
|
||||
UserTable(const std::string &);
|
||||
~UserTable() { delete[] users; }
|
||||
UserTable(const std::string&);
|
||||
~UserTable() {delete[] users;}
|
||||
|
||||
void addUser(const User &);
|
||||
void addUser(const User&);
|
||||
User find(int) const;
|
||||
User find(std::string) const;
|
||||
|
||||
int getNbrUsers() const { return n; }
|
||||
int getNbrUsers() const {
|
||||
return n;
|
||||
}
|
||||
|
||||
void print(std::ostream &) const;
|
||||
void print(std::ostream&) const;
|
||||
|
||||
static const User user_not_found;
|
||||
|
||||
private:
|
||||
private:
|
||||
int capacity{1000};
|
||||
void ensureCapacity(int);
|
||||
int n{0};
|
||||
User *users;
|
||||
User* users;
|
||||
|
||||
friend int testFindNbr(const UserTable ut);
|
||||
};
|
||||
|
|
|
@ -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 <iomanip> // för setw och setfill
|
||||
#include <sstream> // för inputhantering
|
||||
#include <ctime> // time and localtime
|
||||
#include "date.h"
|
||||
|
||||
int Date::daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
// Konstruktor: dagens datum
|
||||
Date::Date() {
|
||||
time_t timer = time(0); // tid i sekunder sedan 1970-01-01
|
||||
tm* locTime = localtime(&timer); // lokal tid
|
||||
year = 1900 + locTime->tm_year;
|
||||
month = 1 + locTime->tm_mon;
|
||||
day = locTime->tm_mday;
|
||||
time_t timer = time(0); // time in seconds since 1970-01-01
|
||||
tm* locTime = localtime(&timer); // broken-down time
|
||||
year = 1900 + locTime->tm_year;
|
||||
month = 1 + locTime->tm_mon;
|
||||
day = locTime->tm_mday;
|
||||
}
|
||||
|
||||
// Konstruktor: specifikt datum
|
||||
Date::Date(int y, int m, int d) : year(y), month(m), day(d) {}
|
||||
Date::Date(int y, int m, int d) {}
|
||||
|
||||
// Get-funktioner
|
||||
int Date::getYear() const {
|
||||
return year;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Date::getMonth() const {
|
||||
return month;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Date::getDay() const {
|
||||
return day;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Gå till nästa dag
|
||||
void Date::next() {
|
||||
day++;
|
||||
if (day > daysPerMonth[month - 1] + (month == 2 && isLeapYear(year))) {
|
||||
day = 1;
|
||||
month++;
|
||||
if (month > 12) {
|
||||
month = 1;
|
||||
year++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kontrollera om ett år är ett skottår
|
||||
bool Date::isLeapYear(int year) {
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
// Overloaded operator<< (output)
|
||||
std::ostream& operator<<(std::ostream& os, const Date& date) {
|
||||
os << std::setw(4) << std::setfill('0') << date.getYear() << '-'
|
||||
<< std::setw(2) << std::setfill('0') << date.getMonth() << '-'
|
||||
<< std::setw(2) << std::setfill('0') << date.getDay();
|
||||
return os;
|
||||
}
|
||||
|
||||
// Overloaded operator>> (input)
|
||||
std::istream& operator>>(std::istream& is, Date& date) {
|
||||
std::string input;
|
||||
is >> input;
|
||||
|
||||
std::istringstream iss(input);
|
||||
char dash1, dash2;
|
||||
int y, m, d;
|
||||
|
||||
if (iss >> y >> dash1 >> m >> dash2 >> d && dash1 == '-' && dash2 == '-') {
|
||||
// Validera månad och dag
|
||||
if (m >= 1 && m <= 12) {
|
||||
int maxDay = Date::daysPerMonth[m - 1];
|
||||
if (m == 2 && Date::isLeapYear(y)) {
|
||||
maxDay = 29; // Februari har 29 dagar under skottår
|
||||
}
|
||||
|
||||
if (d >= 1 && d <= maxDay) {
|
||||
date = Date(y, m, d); // Sätt datumet om det är giltigt
|
||||
return is;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ogiltig inmatning
|
||||
is.setstate(std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
|
|
28
lab4/date.h
28
lab4/date.h
|
@ -1,27 +1,19 @@
|
|||
#ifndef DATE_H
|
||||
#define DATE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class Date {
|
||||
public:
|
||||
Date(); // dagens datum
|
||||
Date(int y, int m, int d); // yyyy-mm-dd
|
||||
int getYear() const; // returnerar året
|
||||
int getMonth() const; // returnerar månaden
|
||||
int getDay() const; // returnerar dagen
|
||||
void next(); // går till nästa dag
|
||||
|
||||
// Overloaded operators
|
||||
friend std::ostream& operator<<(std::ostream& os, const Date& date);
|
||||
friend std::istream& operator>>(std::istream& is, Date& date);
|
||||
|
||||
Date(); // today's date
|
||||
Date(int y, int m, int d); // yyyy-mm-dd
|
||||
int getYear() const; // get the year
|
||||
int getMonth() const; // get the month
|
||||
int getDay() const; // get the day
|
||||
void next(); // advance to next day
|
||||
private:
|
||||
int year; // året (fyra siffror)
|
||||
int month; // månaden (1-12)
|
||||
int day; // dagen (1-...)
|
||||
static int daysPerMonth[12]; // antal dagar i varje månad
|
||||
static bool isLeapYear(int year); // kontrollera skottår
|
||||
int year; // the year (four digits)
|
||||
int month; // the month (1-12)
|
||||
int day; // the day (1-..)
|
||||
static int daysPerMonth[12]; // number of days in each month
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,40 +1,64 @@
|
|||
#include <iostream>
|
||||
#include <iomanip> // for setw and setfill
|
||||
#include "date.h"
|
||||
|
||||
int main() {
|
||||
// Test input och output
|
||||
bool cont = true;
|
||||
while (cont) {
|
||||
std::cout << "Type a date: ";
|
||||
Date aDate;
|
||||
std::cin >> aDate;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
|
||||
if (std::cin.eof()) {
|
||||
cont = false;
|
||||
} else if (!std::cin.good()) {
|
||||
std::cout << "Wrong input format" << std::endl;
|
||||
std::cin.clear();
|
||||
std::cin.ignore(10000, '\n');
|
||||
} else {
|
||||
std::cout << "Output: " << aDate << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Testa 'next' med dagens datum
|
||||
std::cout << "--- Today and more than a month ahead:" << std::endl;
|
||||
Date d1;
|
||||
std::cout << d1 << std::endl;
|
||||
for (int i = 1; i <= 35; ++i) {
|
||||
d1.next();
|
||||
std::cout << d1 << std::endl;
|
||||
}
|
||||
|
||||
// Testa 'next' från nyårsafton
|
||||
std::cout << "--- New Year's Eve and the next day:" << std::endl;
|
||||
Date d2(2013, 12, 31);
|
||||
std::cout << d2 << std::endl;
|
||||
d2.next();
|
||||
std::cout << d2 << std::endl;
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Prints the date d in the format yyyy-mm-dd. You shall replace this
|
||||
* function with an overloaded operator<<, and add an overloaded operator>>.
|
||||
*
|
||||
*/
|
||||
void print(const Date& d) {
|
||||
cout << setw(4) << setfill('0') << d.getYear() << '-';
|
||||
cout << setw(2) << setfill('0') << d.getMonth() << '-';
|
||||
cout << setw(2) << setfill('0') << d.getDay();
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Check input and output of dates. Uncomment the following when you
|
||||
// have added operator>> and operator<<.
|
||||
/*
|
||||
bool cont = true;
|
||||
while (cont) {
|
||||
cout << "Type a date: ";
|
||||
Date aDate;
|
||||
cin >> aDate;
|
||||
if (cin.eof()) {
|
||||
cont = false;
|
||||
} else if (!cin.good()) {
|
||||
cout << "Wrong input format" << endl;
|
||||
// restore stream state and ignore the rest of the line
|
||||
cin.clear();
|
||||
cin.ignore(10000, '\n');
|
||||
}
|
||||
else {
|
||||
cout << "Output: " << aDate << endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 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